Skip to content

Commit

Permalink
Use ForAttributeWithMetadataName whenever possible
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Sep 10, 2022
1 parent e668f2d commit 11c2742
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public sealed class INotifyPropertyChangedGenerator : TransitiveMembersGenerator
/// Initializes a new instance of the <see cref="INotifyPropertyChangedGenerator"/> class.
/// </summary>
public INotifyPropertyChangedGenerator()
: base("global::CommunityToolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute")
: base("CommunityToolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute")
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed class ObservableObjectGenerator : TransitiveMembersGenerator<objec
/// Initializes a new instance of the <see cref="ObservableObjectGenerator"/> class.
/// </summary>
public ObservableObjectGenerator()
: base("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute")
: base("CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute")
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Gather info for all annotated fields
IncrementalValuesProvider<(HierarchyInfo Hierarchy, Result<PropertyInfo?> Info)> propertyInfoWithErrors =
context.SyntaxProvider
.CreateSyntaxProvider(
.ForAttributeWithMetadataName(
"CommunityToolkit.Mvvm.ComponentModel.ObservablePropertyAttribute",
static (node, _) => node is VariableDeclaratorSyntax { Parent: VariableDeclarationSyntax { Parent: FieldDeclarationSyntax { Parent: ClassDeclarationSyntax or RecordDeclarationSyntax, AttributeLists.Count: > 0 } } },
static (context, token) =>
{
Expand All @@ -36,13 +37,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return default;
}

IFieldSymbol fieldSymbol = (IFieldSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!;

// Filter the fields using [ObservableProperty]
if (!fieldSymbol.HasAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservablePropertyAttribute"))
{
return default;
}
IFieldSymbol fieldSymbol = (IFieldSymbol)context.TargetSymbol;

// Produce the incremental models
HierarchyInfo hierarchy = HierarchyInfo.From(fieldSymbol.ContainingType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public sealed class ObservableRecipientGenerator : TransitiveMembersGenerator<Ob
/// Initializes a new instance of the <see cref="ObservableRecipientGenerator"/> class.
/// </summary>
public ObservableRecipientGenerator()
: base("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipientAttribute")
: base("CommunityToolkit.Mvvm.ComponentModel.ObservableRecipientAttribute")
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ namespace CommunityToolkit.Mvvm.SourceGenerators;
public abstract partial class TransitiveMembersGenerator<TInfo> : IIncrementalGenerator
{
/// <summary>
/// The fully qualified name of the attribute type to look for.
/// The fully qualified metadata name of the attribute type to look for.
/// </summary>
private readonly string attributeType;
private readonly string fullyQualifiedAttributeMetadataName;

/// <summary>
/// An <see cref="IEqualityComparer{T}"/> instance to compare intermediate models.
Expand Down Expand Up @@ -51,13 +51,13 @@ public abstract partial class TransitiveMembersGenerator<TInfo> : IIncrementalGe
/// <summary>
/// Initializes a new instance of the <see cref="TransitiveMembersGenerator{TInfo}"/> class.
/// </summary>
/// <param name="attributeType">The fully qualified name of the attribute type to look for.</param>
/// <param name="fullyQualifiedAttributeMetadataName">The fully qualified metadata name of the attribute type to look for.</param>
/// <param name="comparer">An <see cref="IEqualityComparer{T}"/> instance to compare intermediate models.</param>
private protected TransitiveMembersGenerator(string attributeType, IEqualityComparer<TInfo>? comparer = null)
private protected TransitiveMembersGenerator(string fullyQualifiedAttributeMetadataName, IEqualityComparer<TInfo>? comparer = null)
{
this.attributeType = attributeType;
this.fullyQualifiedAttributeMetadataName = fullyQualifiedAttributeMetadataName;
this.comparer = comparer ?? EqualityComparer<TInfo>.Default;
this.classDeclaration = Execute.LoadClassDeclaration(attributeType);
this.classDeclaration = Execute.LoadClassDeclaration(fullyQualifiedAttributeMetadataName);

Execute.ProcessMemberDeclarations(
GetType(),
Expand All @@ -72,25 +72,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Gather all generation info, and any diagnostics
IncrementalValuesProvider<Result<(HierarchyInfo Hierarchy, bool IsSealed, TInfo? Info)>> generationInfoWithErrors =
context.SyntaxProvider
.CreateSyntaxProvider(
static (node, _) => node is ClassDeclarationSyntax { AttributeLists.Count: > 0 },
.ForAttributeWithMetadataName(
this.fullyQualifiedAttributeMetadataName,
static (node, _) => node is ClassDeclarationSyntax classDeclaration && classDeclaration.HasOrPotentiallyHasAttributes(),
(context, token) =>
{
if (!context.SemanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8))
{
return default;
}

INamedTypeSymbol typeSymbol = (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!;

// Filter the types with the target attribute
if (!typeSymbol.TryGetAttributeWithFullyQualifiedName(this.attributeType, out AttributeData? attributeData))
{
return default;
}
INamedTypeSymbol typeSymbol = (INamedTypeSymbol)context.TargetSymbol;

// Gather all generation info, and any diagnostics
TInfo? info = ValidateTargetTypeAndGetInfo(typeSymbol, attributeData, context.SemanticModel.Compilation, out ImmutableArray<Diagnostic> diagnostics);
TInfo? info = ValidateTargetTypeAndGetInfo(typeSymbol, context.Attributes[0], context.SemanticModel.Compilation, out ImmutableArray<Diagnostic> diagnostics);

// If there are any diagnostics, there's no need to compute the hierarchy info at all, just return them
if (diagnostics.Length > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
#if !ROSLYN_4_3
using System.Diagnostics.CodeAnalysis;
#endif
using Microsoft.CodeAnalysis;

namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
Expand Down Expand Up @@ -65,6 +67,7 @@ public static bool HasAttributeWithFullyQualifiedName(this ISymbol symbol, strin
return false;
}

#if !ROSLYN_4_3
/// <summary>
/// Tries to get an attribute with the specified full name.
/// </summary>
Expand All @@ -90,6 +93,7 @@ public static bool TryGetAttributeWithFullyQualifiedName(this ISymbol symbol, st

return false;
}
#endif

/// <summary>
/// Calculates the effective accessibility for a given symbol.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,30 @@ public static bool HasOrPotentiallyHasBaseTypes(this TypeDeclarationSyntax typeD

return false;
}

/// <summary>
/// Checks whether a given <see cref="TypeDeclarationSyntax"/> has or could possibly have any attributes, using only syntax.
/// </summary>
/// <param name="typeDeclaration">The input <see cref="TypeDeclarationSyntax"/> instance to check.</param>
/// <returns>Whether <paramref name="typeDeclaration"/> has or could possibly have any attributes.</returns>
public static bool HasOrPotentiallyHasAttributes(this TypeDeclarationSyntax typeDeclaration)
{
// If the type has any attributes lists, then clearly it can have attributes
if (typeDeclaration.AttributeLists.Count > 0)
{
return true;
}

// If the declaration has no attribute lists, check if the type is partial. If it is, it means
// that there could be another partial declaration with some attribute lists over them.
foreach (SyntaxToken modifier in typeDeclaration.Modifiers)
{
if (modifier.IsKind(SyntaxKind.PartialKeyword))
{
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Gather info for all annotated command methods (starting from method declarations with at least one attribute)
IncrementalValuesProvider<(HierarchyInfo Hierarchy, Result<CommandInfo?> Info)> commandInfoWithErrors =
context.SyntaxProvider
.CreateSyntaxProvider(
.ForAttributeWithMetadataName(
"CommunityToolkit.Mvvm.Input.RelayCommandAttribute",
static (node, _) => node is MethodDeclarationSyntax { Parent: ClassDeclarationSyntax, AttributeLists.Count: > 0 },
static (context, token) =>
{
Expand All @@ -35,17 +36,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return default;
}

IMethodSymbol methodSymbol = (IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!;

// Filter the methods using [RelayCommand]
if (!methodSymbol.TryGetAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.Input.RelayCommandAttribute", out AttributeData? attribute))
{
return default;
}
IMethodSymbol methodSymbol = (IMethodSymbol)context.TargetSymbol;

// Produce the incremental models
HierarchyInfo hierarchy = HierarchyInfo.From(methodSymbol.ContainingType);
CommandInfo? commandInfo = Execute.GetInfo(methodSymbol, attribute, out ImmutableArray<Diagnostic> diagnostics);
CommandInfo? commandInfo = Execute.GetInfo(methodSymbol, context.Attributes[0], out ImmutableArray<Diagnostic> diagnostics);

return (Hierarchy: hierarchy, new Result<CommandInfo?>(commandInfo, diagnostics));
})
Expand Down

0 comments on commit 11c2742

Please sign in to comment.