Skip to content

Commit 0829e5b

Browse files
Merge pull request #107 from thomasclaudiushuber/issue-105
Add support for partial properties
2 parents ae600cb + ec31e60 commit 0829e5b

File tree

7 files changed

+143
-35
lines changed

7 files changed

+143
-35
lines changed

src/MvvmGen.SourceGenerators.Tests/Model/PropertyToGenerateTests.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,62 @@ public class PropertyToGenerateTests
1414
[Fact]
1515
public void ShouldBeEqual()
1616
{
17-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
18-
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
17+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
18+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
1919

2020
Assert.Equal(property1, property2);
2121
}
2222

2323
[Fact]
2424
public void ShouldNotBeEqual1()
2525
{
26-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
27-
var property2 = new PropertyToGenerate("LastName", "string", "_firstName", false);
26+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
27+
var property2 = new PropertyToGenerate("LastName", "string", "_firstName",false, false);
2828

2929
Assert.NotEqual(property1, property2);
3030
}
3131

3232
[Fact]
3333
public void ShouldNotBeEqual2()
3434
{
35-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
36-
var property2 = new PropertyToGenerate("FirstName", "int", "_firstName", false);
35+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
36+
var property2 = new PropertyToGenerate("FirstName", "int", "_firstName",false, false);
3737

3838
Assert.NotEqual(property1, property2);
3939
}
4040

4141
[Fact]
4242
public void ShouldNotBeEqual3()
4343
{
44-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
45-
var property2 = new PropertyToGenerate("FirstName", "string", "_lastName", false);
44+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
45+
var property2 = new PropertyToGenerate("FirstName", "string", "_lastName",false, false);
4646

4747
Assert.NotEqual(property1, property2);
4848
}
4949

5050
[Fact]
5151
public void ShouldNotBeEqual4()
5252
{
53-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
54-
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", true);
53+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false, false);
54+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", true, false);
55+
56+
Assert.NotEqual(property1, property2);
57+
}
58+
59+
[Fact]
60+
public void ShouldNotBeEqual5()
61+
{
62+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false, false);
63+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false, true);
5564

5665
Assert.NotEqual(property1, property2);
5766
}
5867

5968
[Fact]
6069
public void ShouldBeEqual2()
6170
{
62-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
63-
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
71+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false,false);
72+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false,false);
6473

6574
FillAllProperties(property1);
6675
FillAllProperties(property2);
@@ -69,10 +78,10 @@ public void ShouldBeEqual2()
6978
}
7079

7180
[Fact]
72-
public void ShouldNotBeEqual5()
81+
public void ShouldNotBeEqual6()
7382
{
74-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
75-
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
83+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false,false);
84+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false,false);
7685

7786
FillAllProperties(property1);
7887
FillAllProperties(property2);
@@ -83,10 +92,10 @@ public void ShouldNotBeEqual5()
8392
}
8493

8594
[Fact]
86-
public void ShouldNotBeEqual6()
95+
public void ShouldNotBeEqual7()
8796
{
88-
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
89-
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false);
97+
var property1 = new PropertyToGenerate("FirstName", "string", "_firstName",false, false);
98+
var property2 = new PropertyToGenerate("FirstName", "string", "_firstName", false,false);
9099

91100
FillAllProperties(property1);
92101
FillAllProperties(property2);

src/MvvmGen.SourceGenerators.Tests/Model/ViewModelToGenerateTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void ShouldNotBeEqualDifferentPropertiesToGenerate2()
132132
{
133133
var list = (List<PropertyToGenerate>)_viewModelToGenerate2.PropertiesToGenerate!;
134134

135-
list.Add(new PropertyToGenerate("LastName", "string", "_lastName"));
135+
list.Add(new PropertyToGenerate("LastName", "string", "_lastName", false, false));
136136

137137
Assert.NotEqual(_viewModelToGenerate1, _viewModelToGenerate2);
138138
}
@@ -148,6 +148,7 @@ public void ShouldNotBeEqualDifferentPropertiesToGenerate3()
148148
list.Add(new PropertyToGenerate("FirstNameChanged",
149149
originalPropertyToGenerate.PropertyType,
150150
originalPropertyToGenerate.BackingField,
151+
originalPropertyToGenerate.IsPartial,
151152
originalPropertyToGenerate.IsReadOnly));
152153

153154
Assert.NotEqual(_viewModelToGenerate1, _viewModelToGenerate2);
@@ -429,7 +430,7 @@ private static void FillAllProperties(ViewModelToGenerate viewModelToGenerate)
429430

430431
viewModelToGenerate.PropertiesToGenerate = new List<PropertyToGenerate>
431432
{
432-
new("FirstName","string","_firstName",false)
433+
new("FirstName","string","_firstName",false,false)
433434
};
434435

435436
viewModelToGenerate.CommandsToGenerate = new List<CommandToGenerate>

src/MvvmGen.SourceGenerators.Tests/ViewModelGeneratorTests/PropertyAttributeTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,57 @@ public string FirstName
5757
");
5858
}
5959

60+
[InlineData("public")]
61+
[InlineData("private")]
62+
[InlineData("protected")]
63+
[Theory]
64+
public void GeneratePartialProperty(string accessModifier)
65+
{
66+
string propertyName = "FirstName";
67+
string fieldName = "_firstName";
68+
ShouldGenerateExpectedCode(
69+
$@"using MvvmGen;
70+
71+
namespace MyCode
72+
{{
73+
[ViewModel]
74+
public partial class EmployeeViewModel
75+
{{
76+
[Property] {accessModifier} partial string? {propertyName} {{ get; set; }}
77+
}}
78+
}}",
79+
$@"{AutoGeneratedTopContent}
80+
81+
namespace MyCode
82+
{{
83+
partial class EmployeeViewModel : global::MvvmGen.ViewModels.ViewModelBase
84+
{{
85+
public EmployeeViewModel()
86+
{{
87+
this.OnInitialize();
88+
}}
89+
90+
partial void OnInitialize();
91+
92+
private string? _firstName;
93+
94+
{accessModifier} partial string? FirstName
95+
{{
96+
get => {fieldName};
97+
set
98+
{{
99+
if ({fieldName} != value)
100+
{{
101+
{fieldName} = value;
102+
OnPropertyChanged(""FirstName"");
103+
}}
104+
}}
105+
}}
106+
}}
107+
}}
108+
");
109+
}
110+
60111
[InlineData("PropertyName=\"AmazingFirstName\"", "AmazingFirstName")]
61112
[InlineData("\"IncredibleFirstName\"", "IncredibleFirstName")]
62113
[Theory]

src/MvvmGen.SourceGenerators/Generators/PropertyGenerator.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ internal static void GenerateProperties(this ViewModelBuilder vmBuilder, IEnumer
2525
private static void GenerateProperty(ViewModelBuilder vmBuilder, PropertyToGenerate p)
2626
{
2727
vmBuilder.AppendLineBeforeMember();
28-
vmBuilder.Append($"public {p.PropertyType} {p.PropertyName}");
28+
29+
if (p.IsPartial)
30+
{
31+
vmBuilder.AppendLine($"private {p.PropertyType} {p.BackingField};");
32+
vmBuilder.AppendLine();
33+
}
34+
35+
vmBuilder.Append($"{p.AccessModifier} {(p.IsPartial ? "partial " : "")}{p.PropertyType} {p.PropertyName}");
2936

3037
if (p.IsReadOnly)
3138
{

src/MvvmGen.SourceGenerators/Inspectors/ModelMemberInspector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ internal static class ModelMemberInspector
5353
}
5454

5555
propertiesToGenerate.Add(new PropertyToGenerate(
56-
propertySymbol.Name, propertySymbol.Type.ToString(), $"{wrappedModelPropertyName}.{propertySymbol.Name}", propertySymbol.IsReadOnly));
56+
propertySymbol.Name, propertySymbol.Type.ToString(), $"{wrappedModelPropertyName}.{propertySymbol.Name}", isPartial: false, propertySymbol.IsReadOnly));
5757
}
5858
}
5959
}

src/MvvmGen.SourceGenerators/Inspectors/ViewModelMemberInspector.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ internal static (List<CommandToGenerate> CommandsToGenerate,
4141
}
4242
else if (memberSymbol is IPropertySymbol propertySymbol)
4343
{
44-
FindPropertyInvalidations(propertyInvalidationsByGeneratedPropertyName, propertySymbol);
44+
if (propertySymbol.IsPartialDefinition)
45+
{
46+
FindPropertiesToGenerate(propertySymbol, propertiesToGenerate);
47+
}
48+
else // Probably a readonly property with a PropertyInvalidate attribute
49+
{
50+
FindPropertyInvalidations(propertyInvalidationsByGeneratedPropertyName, propertySymbol);
51+
}
4552
}
4653
}
4754

@@ -90,28 +97,50 @@ private static void FindPropertyInvalidations(Dictionary<string, List<string>> p
9097
}
9198
}
9299

93-
private static void FindPropertiesToGenerate(IFieldSymbol fieldSymbol, List<PropertyToGenerate> propertiesToGenerate)
100+
private static void FindPropertiesToGenerate(ISymbol symbol, List<PropertyToGenerate> propertiesToGenerate)
94101
{
95-
var attributeDatas = fieldSymbol.GetAttributes();
102+
var attributeDatas = symbol.GetAttributes();
96103
var propertyAttributeData = attributeDatas.FirstOrDefault(x => x.AttributeClass?.ToDisplayString() == "MvvmGen.PropertyAttribute");
97104

98105
if (propertyAttributeData is not null)
99106
{
100-
var propertyType = fieldSymbol.Type.ToString();
107+
IFieldSymbol? fieldSymbol = null;
108+
IPropertySymbol? propertySymbol = null;
109+
110+
if (symbol.Kind == SymbolKind.Field)
111+
{
112+
fieldSymbol = (IFieldSymbol)symbol;
113+
}
114+
else
115+
{
116+
propertySymbol = (IPropertySymbol)symbol;
117+
}
101118

102-
string? propertyName = null;
103-
var fieldName = fieldSymbol.Name;
119+
string propertyType = symbol.Kind == SymbolKind.Field
120+
? fieldSymbol!.Type.ToString()
121+
: propertySymbol!.Type.ToString();
104122

105-
foreach (var arg in propertyAttributeData.ConstructorArguments)
123+
string? propertyName = propertySymbol?.Name;
124+
var fieldName = fieldSymbol?.Name;
125+
126+
if (fieldName is null)
106127
{
107-
propertyName = arg.Value?.ToString();
128+
fieldName = $"_{propertyName!.Substring(0, 1).ToLower()}{propertyName.Substring(1)}";
108129
}
109130

110-
foreach (var arg in propertyAttributeData.NamedArguments)
131+
if (propertyName is null)
111132
{
112-
if (arg.Key == "PropertyName")
133+
foreach (var arg in propertyAttributeData.ConstructorArguments)
134+
{
135+
propertyName = arg.Value?.ToString();
136+
}
137+
138+
foreach (var arg in propertyAttributeData.NamedArguments)
113139
{
114-
propertyName = arg.Value.Value?.ToString();
140+
if (arg.Key == "PropertyName")
141+
{
142+
propertyName = arg.Value.Value?.ToString();
143+
}
115144
}
116145
}
117146

@@ -186,7 +215,10 @@ private static void FindPropertiesToGenerate(IFieldSymbol fieldSymbol, List<Prop
186215
}
187216
}
188217

189-
propertiesToGenerate.Add(new PropertyToGenerate(propertyName, propertyType, fieldName)
218+
var generateBackingField = symbol.Kind == SymbolKind.Property;
219+
220+
propertiesToGenerate.Add(new PropertyToGenerate(propertyName, propertyType, fieldName,
221+
generateBackingField, isReadOnly: false, accessModifier: (symbol.Kind == SymbolKind.Field ? "public" : propertySymbol!.DeclaredAccessibility.ToString().ToLower()))
190222
{
191223
EventsToPublish = eventsToPublish,
192224
MethodsToCall = methodsToCall

src/MvvmGen.SourceGenerators/Model/PropertyToGenerate.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ namespace MvvmGen.Model
1212
{
1313
internal class PropertyToGenerate : IEquatable<PropertyToGenerate?>
1414
{
15-
public PropertyToGenerate(string propertyName, string propertyType, string backingField, bool isReadOnly = false)
15+
public PropertyToGenerate(string propertyName, string propertyType, string backingField, bool isPartial, bool isReadOnly, string accessModifier = "public")
1616
{
1717
PropertyName = propertyName;
1818
PropertyType = propertyType;
1919
BackingField = backingField;
20+
IsPartial = isPartial;
2021
IsReadOnly = isReadOnly;
22+
AccessModifier = accessModifier;
2123
}
2224

2325
public string PropertyName { get; }
@@ -26,6 +28,10 @@ public PropertyToGenerate(string propertyName, string propertyType, string backi
2628

2729
public string BackingField { get; }
2830

31+
public bool IsPartial { get; }
32+
33+
public string AccessModifier { get; }
34+
2935
public bool IsReadOnly { get; }
3036

3137
public IEnumerable<PropertyEventPublication>? EventsToPublish { get; set; }
@@ -45,6 +51,7 @@ public bool Equals(PropertyToGenerate? other)
4551
PropertyName == other.PropertyName &&
4652
PropertyType == other.PropertyType &&
4753
BackingField == other.BackingField &&
54+
IsPartial == other.IsPartial &&
4855
IsReadOnly == other.IsReadOnly &&
4956
EventsToPublish.SequenceEqualWithNullCheck(other.EventsToPublish) &&
5057
MethodsToCall.SequenceEqualWithNullCheck(other.MethodsToCall) &&
@@ -57,6 +64,7 @@ public override int GetHashCode()
5764
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(PropertyName);
5865
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(PropertyType);
5966
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(BackingField);
67+
hashCode = hashCode * -1521134295 + IsPartial.GetHashCode();
6068
hashCode = hashCode * -1521134295 + IsReadOnly.GetHashCode();
6169
return hashCode;
6270
}

0 commit comments

Comments
 (0)