Skip to content

Commit

Permalink
Merge pull request #14 from paulvarache/feat/partial-changes
Browse files Browse the repository at this point in the history
feat: Add partial methods generation for changed and changing events
  • Loading branch information
rrmanzano committed Jun 3, 2023
2 parents 8ae3ab8 + cb23721 commit 3f9caa1
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,17 @@ private void OnDateTimeChanged(string oldValue)
{
// This method never will fired becuse the parameter is a different type
}

partial void OnDisplayNameChanging(string value)
{
System.Diagnostics.Debug.WriteLine("Method OnDisplayNameChanging fired");
System.Diagnostics.Debug.WriteLine(value);
}

partial void OnDisplayNameChanged(string value)
{
System.Diagnostics.Debug.WriteLine("Method OnDisplayNameChanged fired");
System.Diagnostics.Debug.WriteLine(value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class AutoBindablePropertyGenerator : IncrementalGeneratorBase, IIncremen
private readonly List<Type> TypeImplementations = new() {
typeof(DefaultValue),
typeof(PropertyChanged),
typeof(PropertyChanging),
typeof(DefaultBindingMode),
typeof(ValidateValue)
};
Expand Down Expand Up @@ -169,7 +170,7 @@ private void ProcessBindableProperty(
var nameProperty = fieldSymbol.GetTypedConstant(attributeSymbol, AutoBindableConstants.AttrPropertyName);
this.InitializeImplementations(fieldSymbol, attributeSymbol, classSymbol);

var propertyName = this.ChooseName(fieldName, nameProperty);
var propertyName = ChooseName(fieldName, nameProperty);
if (propertyName?.Length == 0 || propertyName == fieldName)
{
context.ReportDiagnostic(
Expand Down Expand Up @@ -273,7 +274,7 @@ private bool ExistsBodySetter()
return this.Implementations.Any(i => i.SetterImplemented());
}

private string ChooseName(string fieldName, TypedConstant overridenNameOpt)
internal static string ChooseName(string fieldName, TypedConstant overridenNameOpt)
{
if (!overridenNameOpt.IsNull)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ namespace Maui.BindableProperty.Generator.Core.BindableProperty.Implementation;
public class PropertyChanged : IImplementation
{
private TypedConstant OnChangedProperty { get; set; }

protected string PropertyName { get; set; }

private IFieldSymbol FieldSymbol { get; set; }
private INamedTypeSymbol ClassSymbol { get; set; }

public PropertyChanged(IFieldSymbol fieldSymbol, ISymbol attributeSymbol, INamedTypeSymbol classSymbol)
{
this.OnChangedProperty = fieldSymbol.GetTypedConstant(attributeSymbol, AutoBindableConstants.AttrOnChanged);
var nameProperty = fieldSymbol.GetTypedConstant(attributeSymbol, AutoBindableConstants.AttrPropertyName);

this.PropertyName = AutoBindablePropertyGenerator.ChooseName(fieldSymbol.Name, nameProperty);
this.FieldSymbol = fieldSymbol;
this.ClassSymbol = classSymbol;
}
Expand All @@ -22,50 +28,69 @@ public bool SetterImplemented()
return false;
}

public string ProcessBindableParameters()
public virtual string ProcessBindableParameters()
{
return this.OnChangedProperty.GetValue<string>(methodName => {
return $@"propertyChanged: __{methodName}";
});
return $@"propertyChanged: {GetInternalMethodName()}";
}

public void ProcessBodySetter(CodeWriter w)
{
// Not implemented
}

protected virtual string GetInternalMethodName()
{
return $@"__{this.PropertyName}Changed";
}

protected virtual string GetMethodName()
{
return $@"On{this.PropertyName}Changed";
}

public void ProcessImplementationLogic(CodeWriter w)
{
this.OnChangedProperty.GetValue<string>(methodName => {
var methodDefinition = @$"private static void __{methodName}({AutoBindableConstants.FullNameMauiControls}.BindableObject bindable, object oldValue, object newValue)";
var innerMethodName = GetInternalMethodName();

var methodName = GetMethodName();
var methodDefinition = @$"private static void {innerMethodName}({AutoBindableConstants.FullNameMauiControls}.BindableObject bindable, object oldValue, object newValue)";

if (w.ToString().Contains(methodDefinition))
return default;
if (w.ToString().Contains(methodDefinition))
return;

AttributeBuilder.WriteAllAttrGeneratedCodeStrings(w);
using (w.B(methodDefinition))
AttributeBuilder.WriteAllAttrGeneratedCodeStrings(w);
using (w.B(methodDefinition))
{
w._($@"var ctrl = ({this.ClassSymbol.ToDisplayString(CommonSymbolDisplayFormat.DefaultFormat)})bindable;");
if (this.OnChangedProperty.Value is string customMethodName)
{
var methods = this.GetMethodsToCall(methodName);
var methods = this.GetMethodsToCall(customMethodName);
if (methods.Any())
{
w._($@"var ctrl = ({this.ClassSymbol.ToDisplayString(CommonSymbolDisplayFormat.DefaultFormat)})bindable;");
methods.ToList().ForEach(m => {
methods.ToList().ForEach(m =>
{
var count = m.Parameters.Count();
if (count == 0)
w._($@"ctrl.{methodName}();");
w._($@"ctrl.{customMethodName}();");
else if (count == 1)
w._($@"ctrl.{methodName}(({this.FieldSymbol.Type})newValue);");
w._($@"ctrl.{customMethodName}(({this.FieldSymbol.Type})newValue);");
else if (count == 2)
w._($@"ctrl.{methodName}(({this.FieldSymbol.Type})oldValue, ({this.FieldSymbol.Type})newValue);");
w._($@"ctrl.{customMethodName}(({this.FieldSymbol.Type})oldValue, ({this.FieldSymbol.Type})newValue);");
});
}
}
return default;
});
if (this.OnChangedProperty.Value is not string clashingCustomName || clashingCustomName != methodName)
{
w._($@"ctrl.{methodName}(({this.FieldSymbol.Type.ToDisplayString(CommonSymbolDisplayFormat.DefaultFormat)})newValue);");
}
}
if (this.OnChangedProperty.Value is not string clashingCustomCallName || clashingCustomCallName != methodName)
{
w._($@"partial void {methodName}({this.FieldSymbol.Type.ToDisplayString(CommonSymbolDisplayFormat.DefaultFormat)} value);");
}
}

private IEnumerable<IMethodSymbol> GetMethodsToCall(string methodName)
protected virtual IEnumerable<IMethodSymbol> GetMethodsToCall(string methodName)
{
var typeSymbol = this.FieldSymbol.Type;
var methods = this.ClassSymbol.GetMembers(methodName)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.CodeAnalysis;

namespace Maui.BindableProperty.Generator.Core.BindableProperty.Implementation;

public class PropertyChanging : PropertyChanged
{
public PropertyChanging(IFieldSymbol fieldSymbol, ISymbol attributeSymbol, INamedTypeSymbol classSymbol): base(fieldSymbol, attributeSymbol, classSymbol)
{

}

public override string ProcessBindableParameters()
{
return $@"propertyChanging: {GetInternalMethodName()}";
}

protected override string GetInternalMethodName()
{
return $@"__{this.PropertyName}Changing";
}

protected override string GetMethodName()
{
return $@"On{this.PropertyName}Changing";
}

protected override IEnumerable<IMethodSymbol> GetMethodsToCall(string methodName)
{
return Enumerable.Empty<IMethodSymbol>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@
<RepositoryUrl>https://github.com/rrmanzano/maui-bindableproperty-generator</RepositoryUrl>
<PackageId>M.BindableProperty.Generator</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.1" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\README.md">
<Pack>True</Pack>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"Debug": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\Maui.BindableProperty.Generator.Demo\\Maui.BindableProperty.Generator.Demo.csproj"
}
}
}

0 comments on commit 3f9caa1

Please sign in to comment.