Skip to content

Commit eaab7b5

Browse files
Made a UnifiedPropertyGenerator so all code is in one place
1 parent c84d4ed commit eaab7b5

File tree

4 files changed

+111
-139
lines changed

4 files changed

+111
-139
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Text;
5+
using ThunderDesign.Net.Threading.Extentions;
6+
using ThunderDesign.Net.Threading.Objects;
7+
using ThunderDesign.Net_PCL.Threading.Attributes;
8+
9+
namespace SimpleContacts.ViewModels
10+
{
11+
internal partial class TestModel : INotifyPropertyChanged
12+
{
13+
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
14+
private void Test()
15+
{
16+
this.LastName = "John";
17+
}
18+
19+
//public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
20+
//{
21+
// this.NotifyPropertyChanged(PropertyChanged, propertyName);
22+
//}
23+
24+
[BindableProperty(threadSafe:false,notify:false, alsoNotify: new string[] { "FullName" })]
25+
private string _FirstName = String.Empty;
26+
27+
[BindableProperty(alsoNotify: new string[] { "FullName" })]
28+
private string _lastName = String.Empty;
29+
30+
[Property(readOnly: true, threadSafe: false)]
31+
private string _MiddleName = String.Empty;
32+
33+
//private string FullName => $"{LastName}, {FirstName} {MiddleName}";
34+
//protected readonly object _Locker = new object();
35+
}
36+
}

src/ThunderDesign.Net-PCL.SourceGenerators/PropertyGenerator.cs

Lines changed: 0 additions & 120 deletions
This file was deleted.

src/ThunderDesign.Net-PCL.SourceGenerators/PropertyGeneratorHelpers.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,12 @@ public static bool MethodExists(
138138
);
139139
}
140140
}
141+
142+
public struct PropertyFieldInfo
143+
{
144+
public IFieldSymbol FieldSymbol { get; set; }
145+
public INamedTypeSymbol ContainingClass { get; set; }
146+
public AttributeData AttributeData { get; set; }
147+
public FieldDeclarationSyntax FieldDeclaration { get; set; }
148+
}
141149
}

src/ThunderDesign.Net-PCL.SourceGenerators/BindablePropertyGenerator.cs renamed to src/ThunderDesign.Net-PCL.SourceGenerators/UnifiedPropertyGenerator.cs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,37 @@
99
namespace ThunderDesign.Net_PCL.SourceGenerators
1010
{
1111
[Generator]
12-
public class BindablePropertyGenerator : IIncrementalGenerator
12+
public class UnifiedPropertyGenerator : IIncrementalGenerator
1313
{
1414
public void Initialize(IncrementalGeneratorInitializationContext context)
1515
{
16+
// Collect all fields with [BindableProperty] or [Property]
1617
var fieldsWithAttribute = context.SyntaxProvider
1718
.CreateSyntaxProvider(
1819
predicate: static (node, _) => node is FieldDeclarationSyntax fds && fds.AttributeLists.Count > 0,
19-
transform: static (ctx, _) => GetBindableField(ctx)
20+
transform: static (ctx, _) =>
21+
{
22+
var bindable = GetBindableField(ctx);
23+
if (!bindable.Equals(default(BindableFieldInfo)))
24+
return (Class: bindable.ContainingClass, Bindable: bindable, Property: default(PropertyFieldInfo));
25+
var prop = PropertyGeneratorHelpers.GetFieldWithAttribute(ctx, "PropertyAttribute");
26+
if (!prop.Equals(default(PropertyFieldInfo)))
27+
return (Class: prop.ContainingClass, Bindable: default(BindableFieldInfo), Property: prop);
28+
return default;
29+
}
2030
)
21-
.Where(static info => !info.Equals(default(BindableFieldInfo)));
31+
.Where(static info => !info.Equals(default((INamedTypeSymbol, BindableFieldInfo, PropertyFieldInfo))));
2232

23-
// Group fields by containing class
33+
// Group by class
2434
var grouped = fieldsWithAttribute.Collect()
2535
.Select((list, _) => list
26-
.GroupBy(info => info.ContainingClass, SymbolEqualityComparer.Default)
27-
.Select(g => (ClassSymbol: g.Key, Fields: g.ToList()))
36+
.Where(info => info.Class is INamedTypeSymbol)
37+
.GroupBy(info => info.Class, SymbolEqualityComparer.Default)
38+
.Select(g => (
39+
ClassSymbol: g.Key,
40+
BindableFields: g.Select(x => x.Bindable).Where(b => !b.Equals(default(BindableFieldInfo))).ToList(),
41+
PropertyFields: g.Select(x => x.Property).Where(p => !p.Equals(default(PropertyFieldInfo))).ToList()
42+
))
2843
.ToList()
2944
);
3045

@@ -36,10 +51,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3651
foreach (var group in classGroups)
3752
{
3853
var classSymbol = group.ClassSymbol as INamedTypeSymbol;
39-
var fields = group.Fields;
4054
if (classSymbol != null)
4155
{
42-
GenerateBindablePropertyClass(spc, classSymbol, fields, compilation);
56+
GenerateUnifiedPropertyClass(spc, classSymbol, group.BindableFields, group.PropertyFields, compilation);
4357
}
4458
}
4559
});
@@ -74,11 +88,11 @@ private static BindableFieldInfo GetBindableField(GeneratorSyntaxContext context
7488
return default(BindableFieldInfo);
7589
}
7690

77-
// New method to generate all properties and shared members for a class
78-
private static void GenerateBindablePropertyClass(
91+
private static void GenerateUnifiedPropertyClass(
7992
SourceProductionContext context,
8093
INamedTypeSymbol classSymbol,
81-
List<BindableFieldInfo> fields,
94+
List<BindableFieldInfo> bindableFields,
95+
List<PropertyFieldInfo> propertyFields,
8296
Compilation compilation)
8397
{
8498
var implementsINotify = ImplementsInterface(classSymbol, "System.ComponentModel.INotifyPropertyChanged");
@@ -96,28 +110,31 @@ private static void GenerateBindablePropertyClass(
96110
source.AppendLine($"namespace {ns} {{");
97111

98112
source.AppendLine("using ThunderDesign.Net.Threading.Extentions;");
99-
source.AppendLine("using ThunderDesign.Net.Threading.Interfaces;");
100113
source.AppendLine("using ThunderDesign.Net.Threading.Objects;");
114+
if (bindableFields.Count > 0)
115+
{
116+
source.AppendLine("using ThunderDesign.Net.Threading.Interfaces;");
117+
}
101118

102119
source.Append($"partial class {classSymbol.Name}");
103120
var interfaces = new List<string>();
104-
if (!implementsIBindable)
121+
if (bindableFields.Count > 0 && !implementsIBindable)
105122
interfaces.Add("IBindableObject");
106123
if (interfaces.Count > 0)
107124
source.Append(" : " + string.Join(", ", interfaces));
108125
source.AppendLine();
109126
source.AppendLine("{");
110127

111128
// Add event if needed
112-
if (!implementsINotify && !PropertyGeneratorHelpers.EventExists(classSymbol, "PropertyChanged", propertyChangedEventType))
129+
if (bindableFields.Count > 0 && !implementsINotify && !PropertyGeneratorHelpers.EventExists(classSymbol, "PropertyChanged", propertyChangedEventType))
113130
source.AppendLine(" public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
114131

115132
// Add _Locker if needed
116-
if (!inheritsThreadObject && !PropertyGeneratorHelpers.FieldExists(classSymbol, "_Locker"))
133+
if ((!inheritsThreadObject) && !PropertyGeneratorHelpers.FieldExists(classSymbol, "_Locker"))
117134
source.AppendLine(" protected readonly object _Locker = new object();");
118135

119136
// Add OnPropertyChanged if needed
120-
if (!implementsIBindable && !PropertyGeneratorHelpers.MethodExists(
137+
if (bindableFields.Count > 0 && !implementsIBindable && !PropertyGeneratorHelpers.MethodExists(
121138
classSymbol,
122139
"OnPropertyChanged",
123140
new ITypeSymbol[] { stringTypeSymbol },
@@ -130,8 +147,8 @@ public virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMem
130147
}");
131148
}
132149

133-
// Generate all properties
134-
foreach (var info in fields)
150+
// Generate all bindable properties
151+
foreach (var info in bindableFields)
135152
{
136153
var fieldSymbol = info.FieldSymbol;
137154
var fieldName = fieldSymbol.Name;
@@ -200,12 +217,43 @@ public virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMem
200217
}
201218
}
202219

220+
// Generate all regular properties
221+
foreach (var info in propertyFields)
222+
{
223+
var fieldSymbol = info.FieldSymbol;
224+
var fieldName = fieldSymbol.Name;
225+
var propertyName = PropertyGeneratorHelpers.ToPropertyName(fieldName);
226+
var typeName = fieldSymbol.Type.ToDisplayString();
227+
228+
var readOnly = info.AttributeData.ConstructorArguments.Length > 0 && (bool)info.AttributeData.ConstructorArguments[0].Value!;
229+
var threadSafe = info.AttributeData.ConstructorArguments.Length > 1 && (bool)info.AttributeData.ConstructorArguments[1].Value!;
230+
231+
var lockerArg = threadSafe ? "_Locker" : "null";
232+
if (readOnly)
233+
{
234+
source.AppendLine($@"
235+
public {typeName} {propertyName}
236+
{{
237+
get {{ return this.GetProperty(ref {fieldName}, {lockerArg}); }}
238+
}}");
239+
}
240+
else
241+
{
242+
source.AppendLine($@"
243+
public {typeName} {propertyName}
244+
{{
245+
get {{ return this.GetProperty(ref {fieldName}, {lockerArg}); }}
246+
set {{ this.SetProperty(ref {fieldName}, value, {lockerArg}); }}
247+
}}");
248+
}
249+
}
250+
203251
source.AppendLine("}");
204252

205253
if (!string.IsNullOrEmpty(ns))
206254
source.AppendLine("}");
207255

208-
context.AddSource($"{classSymbol.Name}_BindableProperties.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
256+
context.AddSource($"{classSymbol.Name}_AllProperties.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
209257
}
210258

211259
private static bool ImplementsInterface(INamedTypeSymbol type, string interfaceName)

0 commit comments

Comments
 (0)