Skip to content
Draft
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
6 changes: 3 additions & 3 deletions dotnet.slnx
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
<Solution>
<Configurations>
<Platform Name="Any CPU" />
</Configurations>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path=".gitattributes" />
Expand Down Expand Up @@ -40,9 +37,11 @@
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4001.UnitTests/CommunityToolkit.Mvvm.Roslyn4001.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4031.UnitTests/CommunityToolkit.Mvvm.Roslyn4031.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4120.UnitTests/CommunityToolkit.Mvvm.Roslyn4120.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn5000.UnitTests/CommunityToolkit.Mvvm.Roslyn5000.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.UnitTests.csproj" />
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests.shproj" />
<Project Path="tests/CommunityToolkit.Mvvm.UnitTests/CommunityToolkit.Mvvm.UnitTests.shproj" />
</Folder>
Expand All @@ -58,6 +57,7 @@
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.csproj" />
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.csproj" />
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.csproj" />
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.csproj" />
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.shproj" />
<Project Path="src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj" />
</Solution>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.props" />
<Import Project="..\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.projitems" Label="Shared" />

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\FieldWithOrphanedDependentObservablePropertyAttributesAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\FieldReferenceForObservablePropertyFieldAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UnsupportedRoslynVersionForPartialPropertyAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\RequiresCSharpLanguageVersionPreviewAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\RequiresCSharpLanguageVersion14OrPreviewAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidPropertyLevelObservablePropertyAttributeAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UseObservablePropertyOnPartialPropertyAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UnsupportedCSharpLanguageVersionAnalyzer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@
<!-- Also define "ROSLYN_<MAJOR>_<MINOR>_OR_GREATER" build constants, so the generator code can multi-target whenever needed and add any required polyfills -->
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 4.3.1))">$(DefineConstants);ROSLYN_4_3_1_OR_GREATER</DefineConstants>
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 4.12.0))">$(DefineConstants);ROSLYN_4_12_0_OR_GREATER</DefineConstants>
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 5.0.0))">$(DefineConstants);ROSLYN_5_0_0_OR_GREATER</DefineConstants>

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

<!-- Temporary workaround before GA -->
<MvvmToolkitSourceGeneratorRoslynVersion Condition="$([MSBuild]::VersionEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 5.0.0))">5.0.0-2.final</MvvmToolkitSourceGeneratorRoslynVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,18 @@ public static bool IsCandidateValidForCompilation(MemberDeclarationSyntax node,
return false;
}

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

// All other cases are supported, the syntax filter is already validating that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
namespace CommunityToolkit.Mvvm.SourceGenerators;

/// <summary>
/// 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.
/// 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'.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class RequiresCSharpLanguageVersionPreviewAnalyzer : DiagnosticAnalyzer
public sealed class RequiresCSharpLanguageVersion14OrPreviewAnalyzer : DiagnosticAnalyzer
{
/// <inheritdoc/>
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [CSharpLanguageVersionIsNotPreviewForObservableProperty];
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [CSharpLanguageVersionIsNot14OrPreviewForObservableProperty];

/// <inheritdoc/>
public override void Initialize(AnalysisContext context)
Expand All @@ -31,8 +31,12 @@ public override void Initialize(AnalysisContext context)

context.RegisterCompilationStartAction(static context =>
{
// If the language version is set to preview, we'll never emit diagnostics
// If the language version is set to preview or if we are set to at least C# 14.0, we'll never emit diagnostics
#if ROSLYN_5_0_0_OR_GREATER
if (context.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp14))
#else
if (context.Compilation.IsLanguageVersionPreview())
#endif
{
return;
}
Expand Down Expand Up @@ -69,7 +73,7 @@ public override void Initialize(AnalysisContext context)
if (context.Symbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
{
context.ReportDiagnostic(Diagnostic.Create(
CSharpLanguageVersionIsNotPreviewForObservableProperty,
CSharpLanguageVersionIsNot14OrPreviewForObservableProperty,
observablePropertyAttribute.GetLocation(),
context.Symbol));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,17 +691,17 @@ internal static class DiagnosticDescriptors
/// <summary>
/// Gets a <see cref="DiagnosticDescriptor"/> for the C# language version not being sufficient for <c>[ObservableProperty]</c> on partial properties.
/// <para>
/// 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>.
/// 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>.
/// </para>
/// </summary>
public static readonly DiagnosticDescriptor CSharpLanguageVersionIsNotPreviewForObservableProperty = new DiagnosticDescriptor(
public static readonly DiagnosticDescriptor CSharpLanguageVersionIsNot14OrPreviewForObservableProperty = new DiagnosticDescriptor(
id: "MVVMTK0041",
title: "C# language version is not 'preview'",
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)""",
title: "C# language version is not at least 14.0 or 'preview'",
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)""",
category: typeof(ObservablePropertyGenerator).FullName,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
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).",
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).",
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0041");

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ public static bool HasLanguageVersionAtLeastEqualTo(this Compilation compilation
return ((CSharpCompilation)compilation).LanguageVersion >= languageVersion;
}

/// <summary>
/// Checks whether a given compilation (assumed to be for C#) is using a language version greater than a specified one.
/// </summary>
/// <param name="compilation">The <see cref="Compilation"/> to consider for analysis.</param>
/// <param name="languageVersion">The minimum language version to check.</param>
/// <returns>Whether <paramref name="compilation"/> is using a language version greater than the specified one.</returns>
public static bool HasLanguageVersionGreaterThan(this Compilation compilation, LanguageVersion languageVersion)
{
return ((CSharpCompilation)compilation).LanguageVersion > languageVersion;
}

/// <summary>
/// Checks whether a given compilation (assumed to be for C#) is using the preview language version.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;

/// <summary>
/// Extension methods for <see cref="GeneratorExecutionContext"/>, specifically for reporting diagnostics.
/// Extension methods for working with diagnostics from incremental generator pipelines.
/// </summary>
internal static class DiagnosticsExtensions
{
Expand Down
3 changes: 3 additions & 0 deletions src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001.csproj" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120.csproj" ReferenceOutputAssembly="false" />
</ItemGroup>
Expand Down Expand Up @@ -123,9 +124,11 @@
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.0\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.3\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.12\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn5.0\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.0\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.3\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.12\cs" Pack="true" Visible="false" />
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn5.0\cs" Pack="true" Visible="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net8.0;net9.0</TargetFrameworks>
<LangVersion>preview</LangVersion>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<DefineConstants>$(DefineConstants);ROSLYN_4_12_0_OR_GREATER;ROSLYN_5_0_0_OR_GREATER</DefineConstants>

<!-- We're intentionally also using '[ObservableProperty]' on some fields, for testing -->
<NoWarn>$(NoWarn);MVVMTK0042</NoWarn>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\CommunityToolkit.Mvvm.Roslyn4120.UnitTests\Test_ObservablePropertyAttribute_PartialProperties.cs" Link="Test_ObservablePropertyAttribute_PartialProperties.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Dbs.Signed3.Nito.AsyncEx.Context" Version="5.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1" />
<PackageReference Include="MSTest.TestFramework" Version="4.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="System.Reactive" Version="6.1.0" />
<PackageReference Include="System.Text.Json" Version="9.0.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CommunityToolkit.Mvvm.ExternalAssembly.Roslyn4031\CommunityToolkit.Mvvm.ExternalAssembly.Roslyn4031.csproj" />
<ProjectReference Include="..\..\src\CommunityToolkit.Mvvm\CommunityToolkit.Mvvm.csproj" />
<ProjectReference Include="..\..\src\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="contentfiles;build" />
<ProjectReference Include="..\..\src\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="contentfiles;build" />
</ItemGroup>

<Import Project="..\CommunityToolkit.Mvvm.UnitTests\CommunityToolkit.Mvvm.UnitTests.projitems" Label="Shared" />

</Project>
Loading
Loading