Skip to content

Commit 1032f73

Browse files
committed
Add 'WinRTRelayCommandIsNotGeneratedBindablePropertyProviderCompatibleAnalyzer'
1 parent 24064de commit 1032f73

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

src/CommunityToolkit.Mvvm.SourceGenerators/AnalyzerReleases.Shipped.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,4 @@ MVVMTK0042 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator
8787
MVVMTK0043| CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/errors/mvvmtk0043
8888
MVVMTK0044| CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/errors/mvvmtk0044
8989
MVVMTK0045| CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Warning | See https://aka.ms/mvvmtoolkit/errors/mvvmtk0045
90+
MVVMTK0046 | CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator | Warning | See https://aka.ms/mvvmtoolkit/errors/mvvmtk0046

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<Compile Include="$(MSBuildThisFileDirectory)ComponentModel\TransitiveMembersGenerator.Execute.cs" />
4242
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\AsyncVoidReturningRelayCommandMethodAnalyzer.cs" />
4343
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidGeneratedPropertyObservablePropertyAttributeAnalyzer.cs" />
44+
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs" />
4445
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\WinRTObservablePropertyOnFieldsIsNotAotCompatibleAnalyzer.cs" />
4546
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\PropertyNameCollisionObservablePropertyAttributeAnalyzer.cs" />
4647
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidTargetObservablePropertyAttributeAnalyzer.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if ROSLYN_4_11_0_OR_GREATER
6+
7+
using System.Collections.Immutable;
8+
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.Diagnostics;
11+
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
12+
13+
namespace CommunityToolkit.Mvvm.SourceGenerators;
14+
15+
/// <summary>
16+
/// A diagnostic analyzer that generates an error when <c>[RelayCommand]</c> is used on a method inside a type with <c>[GeneratedBindableCustomProperty]</c>.
17+
/// </summary>
18+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
19+
public sealed class WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer : DiagnosticAnalyzer
20+
{
21+
/// <inheritdoc/>
22+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible);
23+
24+
/// <inheritdoc/>
25+
public override void Initialize(AnalysisContext context)
26+
{
27+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
28+
context.EnableConcurrentExecution();
29+
30+
context.RegisterCompilationStartAction(static context =>
31+
{
32+
// This analyzer is only enabled when CsWinRT is also used
33+
if (!context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.IsUsingWindowsRuntimePack())
34+
{
35+
return;
36+
}
37+
38+
// Get the symbol for [RelayCommand] and [GeneratedBindableCustomProperty]
39+
if (context.Compilation.GetTypeByMetadataName("CommunityToolkit.Mvvm.ComponentModel.RelayCommandAttribute") is not INamedTypeSymbol relayCommandSymbol ||
40+
context.Compilation.GetTypeByMetadataName("WinRT.GeneratedBindableCustomPropertyAttribute") is not INamedTypeSymbol generatedBindableCustomPropertySymbol)
41+
{
42+
return;
43+
}
44+
45+
bool isLanguageVersionPreview = context.Compilation.IsLanguageVersionPreview();
46+
47+
context.RegisterSymbolAction(context =>
48+
{
49+
// Ensure we do have a valid method with a containing type we can reference
50+
if (context.Symbol is not IMethodSymbol { ContainingType: INamedTypeSymbol typeSymbol } methodSymbol)
51+
{
52+
return;
53+
}
54+
55+
// If the method is not using [RelayCommand], we can skip it
56+
if (!methodSymbol.TryGetAttributeWithType(relayCommandSymbol, out AttributeData? relayCommandAttribute))
57+
{
58+
return;
59+
}
60+
61+
// If the containing type is using [GeneratedBindableCustomProperty], emit a warning
62+
if (typeSymbol.HasAttributeWithType(generatedBindableCustomPropertySymbol))
63+
{
64+
context.ReportDiagnostic(Diagnostic.Create(
65+
WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible,
66+
relayCommandAttribute.GetLocation(),
67+
methodSymbol));
68+
}
69+
}, SymbolKind.Method);
70+
});
71+
}
72+
}
73+
74+
#endif

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ internal static class DiagnosticDescriptors
750750
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0044");
751751

752752
/// <summary>
753-
/// Gets a <see cref="DiagnosticDescriptor"/> for a CanvasEffect property with invalid accessors.
753+
/// Gets a <see cref="DiagnosticDescriptor"/> for when <c>[ObservableProperty]</c> is used on a field in WinRT scenarios.
754754
/// <para>
755755
/// Format: <c>"The field {0}.{1} using [ObservableProperty] will generate code that is not AOT compatible in WinRT scenarios (such as UWP XAML and WinUI 3 apps), and a partial property should be used instead (as it allows the CsWinRT generators to correctly produce the necessary WinRT marshalling code)"</c>.
756756
/// </para>
@@ -764,4 +764,20 @@ internal static class DiagnosticDescriptors
764764
isEnabledByDefault: true,
765765
description: "Fields using [ObservableProperty] will generate code that is not AOT compatible in WinRT scenarios (such as UWP XAML and WinUI 3 apps), and partial properties should be used instead (as they allow the CsWinRT generators to correctly produce the necessary WinRT marshalling code).",
766766
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0045");
767+
768+
/// <summary>
769+
/// Gets a <see cref="DiagnosticDescriptor"/> for when <c>[RelayCommand]</c> is used on a method in types where <c>[GeneratedBindableCustomProperty]</c> is used.
770+
/// <para>
771+
/// Format: <c>"The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty], which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)"</c>.
772+
/// </para>
773+
/// </summary>
774+
public static readonly DiagnosticDescriptor WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible = new(
775+
id: "MVVMTK0046",
776+
title: "Using [RelayCommand] is not compatible with [GeneratedBindableCustomProperty]",
777+
messageFormat: """The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty], which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)""",
778+
category: typeof(RelayCommandGenerator).FullName,
779+
defaultSeverity: DiagnosticSeverity.Warning,
780+
isEnabledByDefault: true,
781+
description: "Using [RelayCommand] on methods within a type also using [GeneratedBindableCustomProperty] is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator).",
782+
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0046");
767783
}

0 commit comments

Comments
 (0)