-
Notifications
You must be signed in to change notification settings - Fork 121
Add [GeneratedCustomPropertyProvider] generator and analyzers
#2160
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
Draft
Sergio0694
wants to merge
46
commits into
staging/3.0
Choose a base branch
from
user/sergiopedri/bindable-custom-property2
base: staging/3.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
2e99471
Add GeneratedCustomPropertyProviderAttribute class
Sergio0694 b1b3759
Rename IBindableIReadOnlyListAdapter to BindableIReadOnlyListAdapter
Sergio0694 976f8fc
Update marshaller attribute for BindableIReadOnlyListAdapter
Sergio0694 47314a2
Remove IIncrementalGenerator implementation
Sergio0694 659a476
Add SyntaxExtensions with helper methods for Roslyn
Sergio0694 a7622b4
Add extension for attribute analysis with config options
Sergio0694 ac97abd
Add MemberDeclarationSyntaxExtensions for partial checks
Sergio0694 f4fd8ab
WIP
Sergio0694 cecbaa6
Add generic object pool implementation
Sergio0694 9204686
Add PooledArrayBuilder<T> helper for pooled arrays
Sergio0694 07a9d9b
Add IndentedTextWriter helper and update PooledArrayBuilder
Sergio0694 821ee26
Comment out bindable custom property generation logic
Sergio0694 c969b25
Add IsDefaultOrEmpty and Length properties to EquatableArray
Sergio0694 cfab2d1
Add ITypeSymbol extension methods for metadata names
Sergio0694 214ee6c
Add IndentedTextWriter extension methods
Sergio0694 2200f3b
Add HierarchyInfo and TypeInfo models
Sergio0694 e3b36de
Disallow ICustomPropertyProvider on ref types
Sergio0694 2aa2fa4
Add SkipNullValues extension for IncrementalValuesProvider
Sergio0694 0092358
Add EnumerateAllMembers extension for ITypeSymbol
Sergio0694 c6e4352
Add 'this' modifier to SkipNullValues extension method
Sergio0694 3cdf30b
Add methods for fully qualified symbol names
Sergio0694 ec9da7c
WIP
Sergio0694 51191e0
Refactor ToImmutable to use ToImmutableArray
Sergio0694 017cc14
Refactor GetCustomPropertyInfo for clarity and filtering
Sergio0694 a4d7eda
Refactor CustomPropertyProvider models and implementation
Sergio0694 fb40484
Refactor CustomPropertyProviderGenerator emit logic
Sergio0694 24000bd
Add CanBeBoxed property to ITypeSymbolExtensions
Sergio0694 2c74f20
Add IsIndexer property to CustomPropertyInfo record
Sergio0694 710c1a6
Skip static indexer properties in generator
Sergio0694 ee9cddc
Add code generation for ICustomProperty implementation types
Sergio0694 65ee305
Add ICustomPropertyProvider test and XAML references
Sergio0694 b66ae97
Add diagnostic descriptors for custom property provider
Sergio0694 6a9d8c6
Add analyzer release tracking and test implementation
Sergio0694 3783382
Add analyzer for GeneratedCustomPropertyProvider targets
Sergio0694 9117d59
Add analyzer for missing ICustomPropertyProvider interface
Sergio0694 7f134b1
Add SourceGenerator2Test project to solution
Sergio0694 dc0cd5c
Suppress CS8620 warning in generator file
Sergio0694 b7b78d3
Set VersionOverride for CSharp.Workspaces package
Sergio0694 0ca9b0e
Add MSTest package to dependencies
Sergio0694 8f6601d
Add AssemblyInfo with Parallelize attribute to tests
Sergio0694 001f450
Add CSharpGeneratorTest helper for source generator tests
Sergio0694 2929203
Add test for CustomPropertyProviderGenerator
Sergio0694 f26704a
Add custom CSharpAnalyzerTest helper for analyzer tests
Sergio0694 f1ce103
Refactor RunGenerator parameter order and default
Sergio0694 dd62b22
Add tests for GeneratedCustomPropertyProvider analyzer
Sergio0694 2ce2c78
Add .NET 10 reference assemblies support for tests
Sergio0694 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
src/Authoring/WinRT.SourceGenerator2/AnalyzerReleases.Shipped.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| ; Shipped analyzer releases | ||
| ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md | ||
|
|
||
| ## Release 3.0.0 | ||
|
|
||
| ### New Rules | ||
| Rule ID | Category | Severity | Notes | ||
| --------|----------|----------|------- | ||
| CSWINRT2000 | WindowsRuntime.SourceGenerator | Error | Invalid '[GeneratedCustomPropertyProvider]' target type | ||
| CSWINRT2001 | WindowsRuntime.SourceGenerator | Error | Missing 'partial' for '[GeneratedCustomPropertyProvider]' target type | ||
| CSWINRT2002 | WindowsRuntime.SourceGenerator | Error | 'ICustomPropertyProvider' interface type not available |
6 changes: 6 additions & 0 deletions
6
src/Authoring/WinRT.SourceGenerator2/AnalyzerReleases.Unshipped.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| ; Unshipped analyzer release | ||
| ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md | ||
|
|
||
| ### New Rules | ||
| Rule ID | Category | Severity | Notes | ||
| --------|----------|----------|------- |
371 changes: 371 additions & 0 deletions
371
src/Authoring/WinRT.SourceGenerator2/CustomPropertyProviderGenerator.Emit.cs
Large diffs are not rendered by default.
Oops, something went wrong.
184 changes: 184 additions & 0 deletions
184
src/Authoring/WinRT.SourceGenerator2/CustomPropertyProviderGenerator.Execute.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq; | ||
| using System.Threading; | ||
| using Microsoft.CodeAnalysis; | ||
| using Microsoft.CodeAnalysis.CSharp; | ||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
| using WindowsRuntime.SourceGenerator.Models; | ||
|
|
||
| #pragma warning disable CS8620, IDE0046 // TODO: remove 'CS8620' suppression when compiler warning is fixed | ||
|
|
||
| namespace WindowsRuntime.SourceGenerator; | ||
|
|
||
| /// <inheritdoc cref="CustomPropertyProviderGenerator"/> | ||
| public partial class CustomPropertyProviderGenerator | ||
| { | ||
| /// <summary> | ||
| /// Generation methods for <see cref="CustomPropertyProviderGenerator"/>. | ||
| /// </summary> | ||
| private static class Execute | ||
| { | ||
| /// <summary> | ||
| /// Checks whether a target node needs the <c>ICustomPropertyProvider</c> implementation. | ||
| /// </summary> | ||
| /// <param name="node">The target <see cref="SyntaxNode"/> instance to check.</param> | ||
| /// <param name="token">The cancellation token for the operation.</param> | ||
| /// <returns>Whether <paramref name="node"/> is a valid target for the <c>ICustomPropertyProvider</c> implementation.</returns> | ||
| [SuppressMessage("Style", "IDE0060", Justification = "The cancellation token is supplied by Roslyn.")] | ||
| public static bool IsTargetNodeValid(SyntaxNode node, CancellationToken token) | ||
| { | ||
| // We only care about class and struct types, all other types are not valid targets | ||
| if (!node.IsAnyKind(SyntaxKind.ClassDeclaration, SyntaxKind.RecordDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordStructDeclaration)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // If the type is static, abstract, or 'ref', we cannot implement 'ICustomPropertyProvider' on it | ||
| if (((MemberDeclarationSyntax)node).Modifiers.ContainsAny(SyntaxKind.StaticKeyword, SyntaxKind.AbstractKeyword, SyntaxKind.RefKeyword)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // We can only generated the 'ICustomPropertyProvider' implementation if the type is 'partial'. | ||
| // Additionally, all parent type declarations must also be 'partial', for generation to work. | ||
| if (!((MemberDeclarationSyntax)node).IsPartialAndWithinPartialTypeHierarchy) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Tries to get the <see cref="CustomPropertyProviderInfo"/> instance for a given annotated symbol. | ||
| /// </summary> | ||
| /// <param name="context">The <see cref="GeneratorAttributeSyntaxContextWithOptions"/> value to use.</param> | ||
| /// <param name="token">The cancellation token for the operation.</param> | ||
| /// <returns>The resulting <see cref="CustomPropertyProviderInfo"/> instance, if processed successfully.</returns> | ||
| public static CustomPropertyProviderInfo? GetCustomPropertyProviderInfo(GeneratorAttributeSyntaxContextWithOptions context, CancellationToken token) | ||
| { | ||
| bool useWindowsUIXamlProjections = context.GlobalOptions.GetBooleanProperty("CsWinRTUseWindowsUIXamlProjections"); | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| // Make sure that the target interface types are available. This is mostly because when UWP XAML projections | ||
| // are not used, the target project must be referencing the WinUI package to get the right interface type. | ||
| // If we can't find it, we just stop here. A separate diagnostic analyzer will emit the right diagnostic. | ||
| if ((useWindowsUIXamlProjections && context.SemanticModel.Compilation.GetTypeByMetadataName("Windows.UI.Xaml.Data.ICustomPropertyProvider") is null) || | ||
| (!useWindowsUIXamlProjections && context.SemanticModel.Compilation.GetTypeByMetadataName("Microsoft.UI.Xaml.Data.ICustomPropertyProvider") is null)) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| // Ensure we have a valid named type symbol for the annotated type | ||
| if (context.TargetSymbol is not INamedTypeSymbol typeSymbol) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| // Get the type hierarchy (needed to correctly generate sources for nested types too) | ||
| HierarchyInfo typeHierarchy = HierarchyInfo.From(typeSymbol); | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| // Gather all custom properties, depending on how the attribute was used | ||
| EquatableArray<CustomPropertyInfo> customProperties = GetCustomPropertyInfo(typeSymbol, context.Attributes[0], token); | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| return new( | ||
| TypeHierarchy: typeHierarchy, | ||
| CustomProperties: customProperties, | ||
| UseWindowsUIXamlProjections: useWindowsUIXamlProjections); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the <see cref="CustomPropertyInfo"/> values for all applicable properties of a target type. | ||
| /// </summary> | ||
| /// <param name="typeSymbol">The annotated type.</param> | ||
| /// <param name="attribute">The attribute to trigger generation.</param> | ||
| /// <param name="token">The cancellation token for the operation.</param> | ||
| /// <returns>The resulting <see cref="CustomPropertyInfo"/> values for <paramref name="typeSymbol"/>.</returns> | ||
| private static EquatableArray<CustomPropertyInfo> GetCustomPropertyInfo(INamedTypeSymbol typeSymbol, AttributeData attribute, CancellationToken token) | ||
| { | ||
| string?[]? propertyNames = null; | ||
| ITypeSymbol?[]? indexerTypes = null; | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| // If using the attribute constructor taking explicit property names and indexer | ||
| // types, get those names to filter the properties. We'll validate them later. | ||
| if (attribute.ConstructorArguments is [ | ||
| { Kind: TypedConstantKind.Array, Values: var typedPropertyNames }, | ||
| { Kind: TypedConstantKind.Array, Values: var typedIndexerTypes }]) | ||
| { | ||
| propertyNames = [.. typedPropertyNames.Select(tc => tc.Value as string)]; | ||
| indexerTypes = [.. typedIndexerTypes.Select(tc => tc.Value as ITypeSymbol)]; | ||
| } | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| using PooledArrayBuilder<CustomPropertyInfo> customPropertyInfo = new(); | ||
|
|
||
| // Enumerate all members of the annotated type to discover all properties | ||
| foreach (ISymbol symbol in typeSymbol.EnumerateAllMembers()) | ||
| { | ||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| // Only gather public properties, and ignore overrides (we'll find the base definition instead). | ||
| // We also ignore partial property implementations, as we only care about the partial definitions. | ||
| if (symbol is not IPropertySymbol { DeclaredAccessibility: Accessibility.Public, IsOverride: false, PartialDefinitionPart: null } propertySymbol) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // Indexer properties must be instance properties | ||
| if (propertySymbol.IsIndexer && propertySymbol.IsStatic) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // We can only support indexers with a single parameter. | ||
| // If there's more, an analyzer will emit a warning. | ||
| if (propertySymbol.Parameters.Length > 1) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| ITypeSymbol? indexerType = propertySymbol.Parameters.FirstOrDefault()?.Type; | ||
|
|
||
| // Ignore the current property if we have explicit filters and the property doesn't match | ||
| if ((propertySymbol.IsIndexer && indexerTypes?.Contains(indexerType, SymbolEqualityComparer.Default) is false) || | ||
| (!propertySymbol.IsIndexer && propertyNames?.Contains(propertySymbol.Name, StringComparer.Ordinal) is false)) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // If any types in the property signature cannot be boxed, we have to skip the property | ||
| if (!propertySymbol.Type.CanBeBoxed || indexerType?.CanBeBoxed is false) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // Gather all the info for the current property | ||
| customPropertyInfo.Add(new CustomPropertyInfo( | ||
| Name: propertySymbol.Name, | ||
| FullyQualifiedTypeName: propertySymbol.Type.GetFullyQualifiedNameWithNullabilityAnnotations(), | ||
| FullyQualifiedIndexerTypeName: indexerType?.GetFullyQualifiedNameWithNullabilityAnnotations(), | ||
| CanRead: propertySymbol.GetMethod is { DeclaredAccessibility: Accessibility.Public }, | ||
| CanWrite: propertySymbol.SetMethod is { DeclaredAccessibility: Accessibility.Public }, | ||
| IsStatic: propertySymbol.IsStatic)); | ||
| } | ||
|
|
||
| token.ThrowIfCancellationRequested(); | ||
|
|
||
| return customPropertyInfo.ToImmutable(); | ||
| } | ||
| } | ||
| } | ||
29 changes: 29 additions & 0 deletions
29
src/Authoring/WinRT.SourceGenerator2/CustomPropertyProviderGenerator.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using Microsoft.CodeAnalysis; | ||
| using WindowsRuntime.SourceGenerator.Models; | ||
|
|
||
| namespace WindowsRuntime.SourceGenerator; | ||
|
|
||
| /// <summary> | ||
| /// A generator to emit <c>ICustomPropertyProvider</c> implementations for annotated types. | ||
| /// </summary> | ||
| [Generator] | ||
| public sealed partial class CustomPropertyProviderGenerator : IIncrementalGenerator | ||
| { | ||
| /// <inheritdoc/> | ||
| public void Initialize(IncrementalGeneratorInitializationContext context) | ||
| { | ||
| // Gather the info on all types annotated with '[GeneratedCustomPropertyProvider]'. | ||
| IncrementalValuesProvider<CustomPropertyProviderInfo> providerInfo = context.ForAttributeWithMetadataNameAndOptions( | ||
| fullyQualifiedMetadataName: "WindowsRuntime.Xaml.GeneratedCustomPropertyProviderAttribute", | ||
| predicate: Execute.IsTargetNodeValid, | ||
| transform: Execute.GetCustomPropertyProviderInfo) | ||
| .WithTrackingName("CustomPropertyProviderInfo") | ||
| .SkipNullValues(); | ||
|
|
||
| // Write the implementation for all annotated types | ||
| context.RegisterSourceOutput(providerInfo, Emit.WriteCustomPropertyProviderImplementation); | ||
| } | ||
| } |
63 changes: 63 additions & 0 deletions
63
.../Diagnostics/Analyzers/GeneratedCustomPropertyProviderNoAvailableInterfaceTypeAnalyzer.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Immutable; | ||
| using System.Linq; | ||
| using Microsoft.CodeAnalysis; | ||
| using Microsoft.CodeAnalysis.Diagnostics; | ||
|
|
||
| namespace WindowsRuntime.SourceGenerator.Diagnostics; | ||
|
|
||
| /// <summary> | ||
| /// A diagnostic analyzer that validates when <c>[GeneratedCustomPropertyProvider]</c> is used but no interface is available. | ||
| /// </summary> | ||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
| public sealed class GeneratedCustomPropertyProviderNoAvailableInterfaceTypeAnalyzer : DiagnosticAnalyzer | ||
| { | ||
| /// <inheritdoc/> | ||
| public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [DiagnosticDescriptors.GeneratedCustomPropertyProviderNoAvailableInterfaceType]; | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void Initialize(AnalysisContext context) | ||
| { | ||
| context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
| context.EnableConcurrentExecution(); | ||
|
|
||
| context.RegisterCompilationStartAction(static context => | ||
| { | ||
| // Get the '[GeneratedCustomPropertyProvider]' symbol | ||
| if (context.Compilation.GetTypeByMetadataName("WindowsRuntime.Xaml.GeneratedCustomPropertyProviderAttribute") is not { } attributeType) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Try to get any 'ICustomPropertyProvider' symbol | ||
| INamedTypeSymbol? windowsUIXamlCustomPropertyProviderType = context.Compilation.GetTypeByMetadataName("Windows.UI.Xaml.Data.ICustomPropertyProvider"); | ||
| INamedTypeSymbol? microsoftUIXamlCustomPropertyProviderType = context.Compilation.GetTypeByMetadataName("Microsoft.UI.Xaml.Data.ICustomPropertyProvider"); | ||
|
|
||
| // If we have either of them, we'll never need to report any diagnostics | ||
| if (windowsUIXamlCustomPropertyProviderType is not null || microsoftUIXamlCustomPropertyProviderType is not null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| context.RegisterSymbolAction(context => | ||
| { | ||
| // Only classes and structs can be targets of the attribute | ||
| if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class or TypeKind.Struct } typeSymbol) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Emit a diagnostic if the type has the attribute, as it can't be used now | ||
| if (typeSymbol.HasAttributeWithType(attributeType)) | ||
| { | ||
| context.ReportDiagnostic(Diagnostic.Create( | ||
| DiagnosticDescriptors.GeneratedCustomPropertyProviderNoAvailableInterfaceType, | ||
| typeSymbol.Locations.FirstOrDefault(), | ||
| typeSymbol)); | ||
| } | ||
| }, SymbolKind.NamedType); | ||
| }); | ||
| } | ||
| } |
77 changes: 77 additions & 0 deletions
77
...urceGenerator2/Diagnostics/Analyzers/GeneratedCustomPropertyProviderTargetTypeAnalyzer.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Immutable; | ||
| using System.Linq; | ||
| using Microsoft.CodeAnalysis; | ||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
| using Microsoft.CodeAnalysis.Diagnostics; | ||
|
|
||
| namespace WindowsRuntime.SourceGenerator.Diagnostics; | ||
|
|
||
| /// <summary> | ||
| /// A diagnostic analyzer that validates target types for <c>[GeneratedCustomPropertyProvider]</c>. | ||
| /// </summary> | ||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
| public sealed class GeneratedCustomPropertyProviderTargetTypeAnalyzer : DiagnosticAnalyzer | ||
| { | ||
| /// <inheritdoc/> | ||
| public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [ | ||
| DiagnosticDescriptors.GeneratedCustomPropertyProviderInvalidTargetType, | ||
| DiagnosticDescriptors.GeneratedCustomPropertyProviderMissingPartialModifier]; | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void Initialize(AnalysisContext context) | ||
| { | ||
| context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
| context.EnableConcurrentExecution(); | ||
|
|
||
| context.RegisterCompilationStartAction(static context => | ||
| { | ||
| // Get the '[GeneratedCustomPropertyProvider]' symbol | ||
| if (context.Compilation.GetTypeByMetadataName("WindowsRuntime.Xaml.GeneratedCustomPropertyProviderAttribute") is not { } attributeType) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| context.RegisterSymbolAction(context => | ||
| { | ||
| // Only classes and structs can be targets of the attribute | ||
| if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class or TypeKind.Struct } typeSymbol) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Immediately bail if the type doesn't have the attribute | ||
| if (!typeSymbol.HasAttributeWithType(attributeType)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // If the type is static, abstract, or 'ref', it isn't valid | ||
| if (typeSymbol.IsAbstract || typeSymbol.IsStatic || typeSymbol.IsRefLikeType) | ||
| { | ||
| context.ReportDiagnostic(Diagnostic.Create( | ||
| DiagnosticDescriptors.GeneratedCustomPropertyProviderInvalidTargetType, | ||
| typeSymbol.Locations.FirstOrDefault(), | ||
| typeSymbol)); | ||
| } | ||
|
|
||
| // Try to get a syntax reference for the symbol, to resolve the syntax node for it | ||
| if (typeSymbol.DeclaringSyntaxReferences.FirstOrDefault() is SyntaxReference syntaxReference) | ||
| { | ||
| SyntaxNode typeNode = syntaxReference.GetSyntax(context.CancellationToken); | ||
|
|
||
| // If there's no 'partial' modifier in the type hierarchy, the target type isn't valid | ||
| if (!((MemberDeclarationSyntax)typeNode).IsPartialAndWithinPartialTypeHierarchy) | ||
| { | ||
| context.ReportDiagnostic(Diagnostic.Create( | ||
| DiagnosticDescriptors.GeneratedCustomPropertyProviderMissingPartialModifier, | ||
| typeSymbol.Locations.FirstOrDefault(), | ||
| typeSymbol)); | ||
| } | ||
| } | ||
| }, SymbolKind.NamedType); | ||
| }); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'generated' to 'generate' in the comment.