Skip to content

Commit

Permalink
fix: Fix bug with Avalonia and static constructors
Browse files Browse the repository at this point in the history
* fix static constructor error

* A type can have only one static constructor
  • Loading branch information
noliar authored Jul 23, 2024
1 parent b348405 commit 0cd4af8
Show file tree
Hide file tree
Showing 59 changed files with 4,914 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using H.Generators.Extensions;
using System.Collections.Immutable;
using H.Generators.Extensions;
using Microsoft.CodeAnalysis;

namespace H.Generators;
Expand Down Expand Up @@ -32,55 +33,47 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var framework = context.DetectFramework();
var version = context.DetectVersion();

context.SyntaxProvider
var dp1 = context.SyntaxProvider
.ForAttributeWithMetadataNameOfClassesAndRecords("DependencyPropertyGenerator.DependencyPropertyAttribute")
.SelectManyAllAttributesOfCurrentClassSyntax()
.Combine(framework)
.Combine(version)
.SelectAndReportExceptions(static (x, _) => PrepareData(x, isAttached: false), context, Id)
.WhereNotNull()
.CollectAsEquatableArray()
.SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
context.SyntaxProvider
.CollectAsEquatableArray();

var dp2 = context.SyntaxProvider
.ForAttributeWithMetadataNameOfClassesAndRecords("DependencyPropertyGenerator.DependencyPropertyAttribute`1")
.SelectManyAllAttributesOfCurrentClassSyntax()
.Combine(framework)
.Combine(version)
.SelectAndReportExceptions(static (x, _) => PrepareData(x, isAttached: false), context, Id)
.WhereNotNull()
.CollectAsEquatableArray()
.SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
context.SyntaxProvider
.CollectAsEquatableArray();

var adp1 = context.SyntaxProvider
.ForAttributeWithMetadataNameOfClassesAndRecords("DependencyPropertyGenerator.AttachedDependencyPropertyAttribute")
.SelectManyAllAttributesOfCurrentClassSyntax()
.Combine(framework)
.Combine(version)
.SelectAndReportExceptions(static (x, _) => PrepareData(x, isAttached: true), context, Id)
.WhereNotNull()
.CollectAsEquatableArray()
.SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
context.SyntaxProvider
.ForAttributeWithMetadataNameOfClassesAndRecords("DependencyPropertyGenerator.AttachedDependencyPropertyAttribute`1")
.SelectManyAllAttributesOfCurrentClassSyntax()
.Combine(framework)
.Combine(version)
.SelectAndReportExceptions(static (x, _) => PrepareData(x, isAttached: true), context, Id)
.WhereNotNull()
.CollectAsEquatableArray()
.SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
context.SyntaxProvider
.CollectAsEquatableArray();

var adp2 = context.SyntaxProvider
.ForAttributeWithMetadataNameOfClassesAndRecords("DependencyPropertyGenerator.AttachedDependencyPropertyAttribute`2")
.SelectManyAllAttributesOfCurrentClassSyntax()
.Combine(framework)
.Combine(version)
.SelectAndReportExceptions(static (x, _) => PrepareData(x, isAttached: true), context, Id)
.WhereNotNull()
.CollectAsEquatableArray()
.SelectAndReportExceptions(GetSourceCode, context, Id)
.CollectAsEquatableArray();
// A type can have only one static constructor, so combined all four attributes.
// Is there a better performance way?
dp1.Combine(dp2.Combine(adp1.Combine(adp2))).Select((x, _) =>
{
return x.Left.AsImmutableArray().AddRange(x.Right.Left).AddRange(x.Right.Right.Left).AddRange(x.Right.Right.Right).AsEquatableArray();
}).SelectAndReportExceptions(GetSourceCode, context, Id)
.AddSource(context);
}

Expand All @@ -102,40 +95,31 @@ private static (ClassData Class, DependencyPropertyData DependencyProperty)? Pre
return (classData, dependencyPropertyData);
}

private static FileWithName GetSourceCode(
private static EquatableArray<FileWithName> GetSourceCode(
EquatableArray<(ClassData Class, DependencyPropertyData DependencyProperty)> values)
{
if (values.AsImmutableArray().IsDefaultOrEmpty)
{
return FileWithName.Empty;
}

var @class = values.First().Class;
if (@class.Framework is not Framework.Avalonia)
{
return FileWithName.Empty;
return ImmutableArray<FileWithName>.Empty.AsEquatableArray();
}

var dependencyProperties = values
.Select(static x => x.DependencyProperty)
.ToArray();
if (dependencyProperties.Where(static property => !property.IsDirect).Any())
return values.Where(x => x.Class.Framework is Framework.Avalonia).GroupBy(x => x.Class, x => x.DependencyProperty).Select(a =>
{
var text = Sources.GenerateStaticConstructor(
@class,
dependencyProperties
.Where(static property => !property.IsDirect)
a.Key,
a.Where(static property => !property.IsDirect)
.ToArray());

if (!string.IsNullOrWhiteSpace(text))
{
return new FileWithName(
Name: $"{@class.FullName}.StaticConstructor.g.cs",
Name: $"{a.Key.FullName}.StaticConstructor.g.cs",
Text: text);
}
}

return FileWithName.Empty;
else
{
return FileWithName.Empty;
}
}).ToImmutableArray().AsEquatableArray();
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
Id: CS8019,
Title: Unnecessary using directive,
Severity: Hidden,
WarningLevel: 1,
Location: : (0,0)-(0,15),
HelpLink: https://msdn.microsoft.com/query/roslyn.query?appId=roslyn&k=k(CS8019),
MessageFormat: Unnecessary using directive.,
Message: Unnecessary using directive.,
Category: Compiler,
CustomTags: [
Compiler,
Telemetry
]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//HintName: DefaultBindingMode.g.cs
#nullable enable

namespace DependencyPropertyGenerator;

/// <summary>
/// Describes the direction of the data flow in a binding.
/// </summary>
internal enum DefaultBindingMode
{
/// <summary>
/// Causes changes to either the source property or the target property to automatically
/// update the other. This type of binding is appropriate for editable forms or other
/// fully-interactive UI scenarios.
/// </summary>
TwoWay = 0,

/// <summary>
/// Updates the binding target (target) property when the binding source (source)
/// changes. This type of binding is appropriate if the control being bound is implicitly
/// read-only. For instance, you may bind to a source such as a stock ticker. Or
/// perhaps your target property has no control interface provided for making changes,
/// such as a data-bound background color of a table. If there is no need to monitor
/// the changes of the target property, using the System.Windows.Data.BindingMode.OneWay
/// binding mode avoids the overhead of the System.Windows.Data.BindingMode.TwoWay
/// binding mode.
/// </summary>
OneWay = 1,

/// <summary>
/// Updates the binding target when the application starts or when the data context
/// changes. This type of binding is appropriate if you are using data where either
/// a snapshot of the current state is appropriate to use or the data is truly static.
/// This type of binding is also useful if you want to initialize your target property
/// with some value from a source property and the data context is not known in advance.
/// This is essentially a simpler form of System.Windows.Data.BindingMode.OneWay
/// binding that provides better performance in cases where the source value does
/// not change.
/// </summary>
OneTime = 2,

/// <summary>
/// Updates the source property when the target property changes.
/// </summary>
OneWayToSource = 3,

/// <summary>
/// Uses the default System.Windows.Data.Binding.Mode value of the binding target.
/// The default value varies for each dependency property. In general, user-editable
/// control properties, such as those of text boxes and check boxes, default to two-way
/// bindings, whereas most other properties default to one-way bindings. A programmatic
/// way to determine whether a dependency property binds one-way or two-way by default
/// is to get the property metadata of the property using System.Windows.DependencyProperty.GetMetadata(System.Type)
/// and then check the Boolean value of the System.Windows.FrameworkPropertyMetadata.BindsTwoWayByDefault
/// property.
/// </summary>
Default = 4,
}
Loading

0 comments on commit 0cd4af8

Please sign in to comment.