diff --git a/.gitignore b/.gitignore
index 20879b3..0eba03e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,9 +26,6 @@
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/
-# Debug artifacts
-launchSettings.json
-
# Prevent accidental re-checkin of NuGet.exe
NuGet.exe
diff --git a/Aspid.MVVM.Generators.sln b/Aspid.MVVM.Generators.sln
index 3c82bd3..a882cb7 100644
--- a/Aspid.MVVM.Generators.sln
+++ b/Aspid.MVVM.Generators.sln
@@ -17,9 +17,7 @@ Global
{8396B53C-70A1-422E-9E40-9AEBB223F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8396B53C-70A1-422E-9E40-9AEBB223F6B3}.Release|Any CPU.Build.0 = Release|Any CPU
{A1DE8BA3-CAEC-4823-99D1-720059565792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A1DE8BA3-CAEC-4823-99D1-720059565792}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1DE8BA3-CAEC-4823-99D1-720059565792}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A1DE8BA3-CAEC-4823-99D1-720059565792}.Release|Any CPU.Build.0 = Release|Any CPU
{837E3102-786A-44C6-9490-1C77BE8D26C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{837E3102-786A-44C6-9490-1C77BE8D26C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{837E3102-786A-44C6-9490-1C77BE8D26C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/Aspid.MVVM.Generators.Sample.csproj b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/Aspid.MVVM.Generators.Sample.csproj
index 38d009e..6ee56e6 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/Aspid.MVVM.Generators.Sample.csproj
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/Aspid.MVVM.Generators.Sample.csproj
@@ -1,4 +1,4 @@
-
+
net9.0
@@ -14,4 +14,15 @@
+
+
+
+ Source\%(RecursiveDir)%(Filename)%(Extension)
+
+
+
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty1Vm.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty1Vm.cs
new file mode 100644
index 0000000..5a76410
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty1Vm.cs
@@ -0,0 +1,36 @@
+namespace Aspid.MVVM.Generators.Sample;
+
+[ViewModel]
+public partial class ExProperty1Vm
+{
+ private string _firstName = string.Empty;
+ private string _lastName = string.Empty;
+
+ [Bind]
+ public string FirstName
+ {
+ get => _firstName;
+ private set
+ {
+ if (SetFirstNameField(ref _firstName, value))
+ OnFullNamePropertyChanged();
+ }
+ }
+
+ [Bind]
+ [BindAlso(nameof(FullName))]
+ public string LastName
+ {
+ get => _lastName;
+ private set
+ {
+ if (_lastName == value) return;
+
+ _lastName = value;
+ OnLastNamePropertyChanged();
+ }
+ }
+
+ [Bind]
+ public string FullName => $"{FirstName} {LastName}";
+}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty2Vm.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty2Vm.cs
new file mode 100644
index 0000000..2d080d6
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators.Sample/ExProperty2Vm.cs
@@ -0,0 +1,36 @@
+namespace Aspid.MVVM.Generators.Sample;
+
+[ViewModel]
+public partial class ExProperty2Vm
+{
+ private string _firstName = string.Empty;
+ private string _lastName = string.Empty;
+
+ [Bind]
+ public string FirstName
+ {
+ get => _firstName;
+ private set
+ {
+ if (SetField(ref _firstName, value))
+ OnPropertyChanged(nameof(FullName));
+ }
+ }
+
+ [Bind]
+ [BindAlso(nameof(FullName))]
+ public string LastName
+ {
+ get => _lastName;
+ private set
+ {
+ if (_lastName == value) return;
+
+ _lastName = value;
+ OnPropertyChanged();
+ }
+ }
+
+ [Bind]
+ public string FullName => $"{_firstName} {_lastName}";
+}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Aspid.MVVM.Generators.csproj b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Aspid.MVVM.Generators.csproj
index 19aae24..0441d35 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Aspid.MVVM.Generators.csproj
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Aspid.MVVM.Generators.csproj
@@ -4,7 +4,7 @@
netstandard2.0
false
enable
- 13
+ 14
true
true
@@ -12,12 +12,15 @@
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Find.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Find.cs
index 255c714..b1518ce 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Find.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Find.cs
@@ -2,27 +2,27 @@
using System.Threading;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using System.Runtime.CompilerServices;
-using Aspid.MVVM.Generators.Binders.Data;
-using Aspid.MVVM.Generators.Descriptions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Aspid.MVVM.Generators.Generators.Binders.Data;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.Binders;
+namespace Aspid.MVVM.Generators.Generators.Binders;
public partial class BinderGenerator
{
- private static FoundForGenerator FindBinders(GeneratorSyntaxContext context,
+ private static BinderData? FindBinders(GeneratorSyntaxContext context,
CancellationToken cancellationToken)
{
Debug.Assert(context.Node is TypeDeclarationSyntax);
var candidate = Unsafe.As(context.Node);
var symbol = context.SemanticModel.GetDeclaredSymbol(candidate, cancellationToken);
- if (symbol is null) return default;
- if (!symbol.HasInterfaceInSelfOrBases(Classes.IBinder, out var binderInterface)) return default;
+ if (symbol is null) return null;
+ if (!symbol.TryGetAnyInterfaceInSelfAndBases(out var binderInterface, Classes.IBinder)) return null;
var hasBinderLogInBaseType = false;
const string setValueName = "SetValue";
@@ -35,16 +35,22 @@ private static FoundForGenerator FindBinders(GeneratorSyntaxContext
.Any(binderMethod =>
{
if (binderMethod.Name is not setValueName) return false;
-
+
return binderMethod.EqualsSignature(method) &&
method.ExplicitInterfaceImplementations.Length != 0;
});
-
- if (methodsExplicitImplemented) return default;
- if (!hasBinderLogInBaseType
+ if (methodsExplicitImplemented) return null;
+
+ // Check if IAnyBinder.SetValue is already explicitly implemented
+ if (method.IsGenericMethod && method.Name == setValueName
+ && method.ExplicitInterfaceImplementations.Any(m =>
+ m.ContainingType.Name is "IAnyBinder"))
+ return null;
+
+ if (!hasBinderLogInBaseType
&& !SymbolEqualityComparer.Default.Equals(type, symbol)
- && method.HasAnyAttribute(Classes.BinderLogAttribute))
+ && method.HasAnyAttributeInSelf(Classes.BinderLogAttribute))
{
hasBinderLogInBaseType = true;
}
@@ -55,17 +61,25 @@ private static FoundForGenerator FindBinders(GeneratorSyntaxContext
foreach (var method in symbol.GetMembers().OfType())
{
- if (method.Parameters.Length != 1) continue;
+ if (method.Parameters.Length is not 1) continue;
if (method.NameFromExplicitImplementation() != setValueName) continue;
- if (!symbol.HasInterfaceInSelfOrBases($"{Classes.IBinder.FullName}<{method.Parameters[0].Type.ToDisplayString()}>")) continue;
-
- if (method.HasAnyAttribute(Classes.BinderLogAttribute) &&
+
+ var isIBinderMethod = !method.IsGenericMethod
+ && symbol.HasAnyInterfaceInSelfAndBases(
+ $"{Classes.IBinder.FullName}<{method.Parameters[0].Type.ToDisplayString()}>");
+
+ var isIAnyBinderMethod = method is { IsGenericMethod: true, TypeParameters.Length: 1 }
+ && symbol.HasAnyInterfaceInSelfAndBases(Classes.IAnyBinder.FullName);
+
+ if (!isIBinderMethod && !isIAnyBinderMethod) continue;
+
+ if (method.HasAnyAttributeInSelf(Classes.BinderLogAttribute) &&
!method.ExplicitInterfaceImplementations.Any())
binderLogMethods.Add(method);
}
-
- if (binderLogMethods.Count == 0) return default;
-
- return new FoundForGenerator(new BinderData(symbol, candidate, hasBinderLogInBaseType, binderLogMethods));
+
+ return binderLogMethods.Count is 0
+ ? null
+ : new BinderData(symbol, candidate, hasBinderLogInBaseType, binderLogMethods);
}
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Generate.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Generate.cs
index c99b203..17d6520 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Generate.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.Generate.cs
@@ -1,10 +1,10 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Binders.Body;
-using Aspid.MVVM.Generators.Binders.Data;
-using Aspid.MVVM.Generators.Descriptions;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Binders.Body;
+using Aspid.MVVM.Generators.Generators.Binders.Data;
+using Aspid.MVVM.Generators.Generators.Descriptions;
-namespace Aspid.MVVM.Generators.Binders;
+namespace Aspid.MVVM.Generators.Generators.Binders;
public partial class BinderGenerator
{
@@ -14,7 +14,7 @@ private static void GenerateCode(SourceProductionContext context, BinderData bin
{
var declaration = binderData.Declaration;
var @namespace = declaration.GetNamespaceName();
- var declarationText = declaration.GetDeclarationText();
+ var declarationText = new DeclarationText(declaration);
GenerateBinderLog(@namespace, new BinderDataSpan(binderData), context, declarationText);
}
@@ -31,15 +31,15 @@ private static void GenerateBinderLog(
#if DEBUG
code.AppendLine($"#if !{Defines.ASPID_MVVM_BINDER_LOG_DISABLED}")
- .AppendClassBegin(@namespace, declarationText)
+ .BeginClass(@namespace, declarationText)
.AppendBinderLogBody(data)
- .AppendClassEnd(@namespace)
+ .EndClass(@namespace)
.AppendLine("#endif");
#else
- code.AppendLine($"#if {Defines.UNITY_EDITOR} && !{Defines.ASPID_MVVM_BINDER_LOG_DISABLED}")
- .AppendClassBegin(@namespace, declarationText)
+ code.AppendLine($"#if {Aspid.Generators.Helper.Unity.Defines.UNITY_EDITOR} && !{Defines.ASPID_MVVM_BINDER_LOG_DISABLED}")
+ .BeginClass(@namespace, declarationText)
.AppendBinderLogBody(data)
- .AppendClassEnd(@namespace)
+ .EndClass(@namespace)
.Append("#endif");
#endif
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.cs
index 196ad03..f0b64e8 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/BinderGenerator.cs
@@ -3,16 +3,17 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-namespace Aspid.MVVM.Generators.Binders;
+namespace Aspid.MVVM.Generators.Generators.Binders;
[Generator]
public partial class BinderGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+ // ReSharper disable once NullableWarningSuppressionIsUsed
var provider = context.SyntaxProvider.CreateSyntaxProvider(SyntacticPredicate, FindBinders)
- .Where(foundForSourceGenerator => foundForSourceGenerator.IsNeed)
- .Select((foundForSourceGenerator, _) => foundForSourceGenerator.Container);
+ .Where(data => data.HasValue)
+ .Select((data, _) => data!.Value);
context.RegisterSourceOutput(
source: provider,
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Body/BinderLogBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Body/BinderLogBody.cs
index 51fec3b..06bba5e 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Body/BinderLogBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Body/BinderLogBody.cs
@@ -1,127 +1,178 @@
using System;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Binders.Data;
-using Aspid.MVVM.Generators.Descriptions;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Binders.Data;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.Generators.Helper.Unity.UnityClasses;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.Binders.Body;
+namespace Aspid.MVVM.Generators.Generators.Binders.Body;
// ReSharper disable InconsistentNaming
public static class BinderLogBody
{
- private const string GeneratedAttribute = General.GeneratedCodeLogBinderAttribute;
-
- private static readonly string List = Classes.List.Global;
- private static readonly string IBinder = Classes.IBinder.Global;
- private static readonly string Exception = Classes.Exception.Global;
- private static readonly string SerializeFieldAttribute = Classes.SerializeField.Global;
-
- public static CodeWriter AppendBinderLogBody(this CodeWriter code, in BinderDataSpan data)
- {
- var hasBinderLogInBaseType = data.HasBinderLogInBaseType;
+ private static readonly string IBinder = Classes.IBinder;
+ private static readonly string IAnyBinder = Classes.IAnyBinder;
+ private static readonly string Exception = Aspid.Generators.Helper.Classes.Exception;
- if (!hasBinderLogInBaseType)
+ extension(CodeWriter code)
+ {
+ public CodeWriter AppendBinderLogBody(in BinderDataSpan data)
{
- code.AppendProfilerMarkers(data)
- .AppendProperties(data);
- }
+ var hasBinderLogInBaseType = data.HasBinderLogInBaseType;
+
+ if (!hasBinderLogInBaseType)
+ {
+ code.AppendProfilerMarkers(data)
+ .AppendProperties(data);
+ }
- code.AppendSetValueMethods(data.Methods);
+ code.AppendSetValueMethods(data.Methods);
- if (!hasBinderLogInBaseType)
- code.AppendAddLogMethod(data);
+ if (!hasBinderLogInBaseType)
+ code.AppendAddLogMethod(data);
- return code;
- }
+ return code;
+ }
- private static CodeWriter AppendProfilerMarkers(this CodeWriter code, in BinderDataSpan data)
- {
- var modifier = data.Symbol.IsSealed ? "private" : "protected";
- var className = data.Declaration.Identifier.Text;
+ private CodeWriter AppendProfilerMarkers(in BinderDataSpan data)
+ {
+ var modifier = data.Symbol.IsSealed ? "private" : "protected";
+ var className = data.Declaration.Identifier.Text;
- code.AppendLine($"{modifier} static readonly {Classes.ProfilerMarker.Global} SetValueMarker = new(\"{className}.SetValue\");");
- return code.AppendLine();
- }
+ code.AppendLine($"{modifier} static readonly {ProfilerMarker} SetValueMarker = new(\"{className}.SetValue\");");
+ return code.AppendLine();
+ }
- private static CodeWriter AppendProperties(this CodeWriter code, in BinderDataSpan data)
- {
- var modifier = data.Symbol.IsSealed ? "private" : "protected";
+ private CodeWriter AppendProperties(in BinderDataSpan data)
+ {
+ var modifier = data.Symbol.IsSealed ? "private" : "protected";
- code.AppendMultiline(
- $"""
- {GeneratedAttribute}
- [{SerializeFieldAttribute}] private bool _isDebug;
-
- // TODO Add Custom Property
- {GeneratedAttribute}
- [{SerializeFieldAttribute}] private {Classes.List.Global} _log;
-
- {GeneratedAttribute}
- {modifier} bool IsDebug => _isDebug;
- """)
- .AppendLine();
+ code.AppendMultiline(
+ $"""
+ {GeneratedCodeLogBinderAttribute}
+ [{SerializeField}] private bool _isDebug;
+
+ // TODO Add Custom Property
+ {GeneratedCodeLogBinderAttribute}
+ [{SerializeField}] private {List_1} _log;
+
+ {GeneratedCodeLogBinderAttribute}
+ {modifier} bool IsDebug => _isDebug;
+ """)
+ .AppendLine();
- return code;
- }
+ return code;
+ }
- private static CodeWriter AppendSetValueMethods(this CodeWriter code, in ReadOnlySpan methods)
- {
- code.AppendLoop(methods, method =>
+ private CodeWriter AppendSetValueMethods(in ReadOnlySpan methods)
+ {
+ foreach (var method in methods)
+ {
+ if (method.IsGenericMethod)
+ code.AppendIAnyBinderSetValueMethod(method);
+ else
+ code.AppendIBinderSetValueMethod(method);
+
+ code.AppendLine();
+ }
+
+ return code;
+ }
+
+ private void AppendIBinderSetValueMethod(IMethodSymbol method)
{
var parameterName = method.Parameters[0].Name;
var parameterType = method.Parameters[0].Type.ToDisplayStringGlobal();
-
+
code.AppendMultiline(
$$"""
- {{GeneratedAttribute}}
- void {{IBinder}}<{{parameterType}}>.{{method.Name}}({{parameterType}} {{parameterName}})
- {
- if (IsDebug)
- {
- try
- {
- using (SetValueMarker.Auto())
- {
- SetValue({{parameterName}});
- }
-
- AddLog($"SetValue: {{{parameterName}}}");
- }
- catch ({{Exception}} e)
- {
- AddLog($"Exception: {e}. {nameof({{parameterName}})}: {{parameterName}}");
- throw;
- }
- }
- else
- {
- using (SetValueMarker.Auto())
- {
- SetValue({{parameterName}});
- }
- }
- }
- """)
- .AppendLine();
- });
+ {{GeneratedCodeLogBinderAttribute}}
+ void {{IBinder}}<{{parameterType}}>.{{method.Name}}({{parameterType}} {{parameterName}})
+ {
+ if (IsDebug)
+ {
+ try
+ {
+ using (SetValueMarker.Auto())
+ {
+ SetValue({{parameterName}});
+ }
- return code;
- }
+ AddLog($"SetValue: {{{parameterName}}}");
+ }
+ catch ({{Exception}} e)
+ {
+ AddLog($"Exception: {e}. {nameof({{parameterName}})}: {{parameterName}}");
+ throw;
+ }
+ }
+ else
+ {
+ using (SetValueMarker.Auto())
+ {
+ SetValue({{parameterName}});
+ }
+ }
+ }
+ """);
+ }
- private static CodeWriter AppendAddLogMethod(this CodeWriter code, in BinderDataSpan data)
- {
- var modifier = data.Symbol.IsSealed ? "private" : "protected";
+ private void AppendIAnyBinderSetValueMethod(IMethodSymbol method)
+ {
+ var typeParamName = method.TypeParameters[0].Name;
+ var parameterName = method.Parameters[0].Name;
+
+ code.AppendMultiline(
+ $$"""
+ {{GeneratedCodeLogBinderAttribute}}
+ void {{IAnyBinder}}.{{method.Name}}<{{typeParamName}}>({{typeParamName}} {{parameterName}})
+ {
+ if (IsDebug)
+ {
+ try
+ {
+ using (SetValueMarker.Auto())
+ {
+ SetValue({{parameterName}});
+ }
+
+ AddLog($"SetValue: {{{parameterName}}}");
+ }
+ catch ({{Exception}} e)
+ {
+ AddLog($"Exception: {e}. {nameof({{parameterName}})}: {{parameterName}}");
+ throw;
+ }
+ }
+ else
+ {
+ using (SetValueMarker.Auto())
+ {
+ SetValue({{parameterName}});
+ }
+ }
+ }
+ """);
+ }
+
+ private CodeWriter AppendAddLogMethod(in BinderDataSpan data)
+ {
+ var modifier = data.Symbol.IsSealed ? "private" : "protected";
- code.AppendMultiline(
- $$"""
- {{GeneratedAttribute}}
- {{modifier}} void AddLog(string log)
- {
- _log ??= new {{List}}();
- _log.Add(log);
- }
- """);
+ code.AppendMultiline(
+ $$"""
+ {{GeneratedCodeLogBinderAttribute}}
+ {{modifier}} void AddLog(string log)
+ {
+ _log ??= new {{List_1}}();
+ _log.Add(log);
+ }
+ """);
- return code;
+ return code;
+ }
}
+
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderData.cs
index a870d34..f2aebe0 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderData.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderData.cs
@@ -3,7 +3,7 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-namespace Aspid.MVVM.Generators.Binders.Data;
+namespace Aspid.MVVM.Generators.Generators.Binders.Data;
public readonly struct BinderData(
INamedTypeSymbol symbol,
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderDataSpan.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderDataSpan.cs
index e3a607b..f2a5ddd 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderDataSpan.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Binders/Data/BinderDataSpan.cs
@@ -2,7 +2,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-namespace Aspid.MVVM.Generators.Binders.Data;
+namespace Aspid.MVVM.Generators.Generators.Binders.Data;
public readonly ref struct BinderDataSpan(BinderData data)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Body/CreateFromBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Body/CreateFromBody.cs
deleted file mode 100644
index 4bead8e..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Body/CreateFromBody.cs
+++ /dev/null
@@ -1,313 +0,0 @@
-using System;
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.CreateFrom.Data;
-
-namespace Aspid.MVVM.Generators.CreateFrom.Body;
-
-// ReSharper disable InconsistentNaming
-public static class CreateFromBody
-{
- private const string GeneratedAttribute = General.GeneratedCodeCreateFromAttribute;
-
- private static readonly string List = Classes.List.Global;
- private static readonly string Func = Classes.Func.Global;
- private static readonly string Span = Classes.Span.Global;
- private static readonly string IList = Classes.IList.Global;
- private static readonly string IEnumerable = Classes.IEnumerable.Global;
- private static readonly string ReadOnlySpan = Classes.ReadOnlySpan.Global;
- private static readonly SymbolEqualityComparer Comparer = SymbolEqualityComparer.Default;
-
- public static CodeWriter AppendCreateFromBody(this CodeWriter code, in CreateFromDataSpan data)
- {
- if (data.Constructor.Parameters.Length == 0) return code;
- var parameters = GetParameters(data.Constructor, data.FromType);
-
- code.AppendLine($"[{Classes.MethodImplAttribute.Global}({Classes.MethodImplOptions.Global}.AggressiveInlining)]")
- .AppendMethodDeclaration(data, parameters, ParameterType.None, ParameterType.None)
- .AppendMultiline(
- $$"""
- {
- return new({{parameters.Constructor(parameters.From)}});
- }
- """)
- .AppendLine();
-
- code.AppendArrayMethodBody(data, ParameterType.Array, parameters)
- .AppendArrayMethodBody(data, ParameterType.Span, parameters)
- .AppendArrayMethodBody(data, ParameterType.ReadOnlySpan, parameters)
- .AppendArrayMethodBody(data, ParameterType.List, parameters);
-
- code.AppendListMethodBody(data, ParameterType.Array, parameters)
- .AppendListMethodBody(data, ParameterType.List, parameters)
- .AppendListMethodBody(data, ParameterType.Span, parameters)
- .AppendListMethodBody(data, ParameterType.ReadOnlySpan, parameters)
- .AppendListMethodBody(data ,ParameterType.Enumerable, parameters);
-
- code.AppendIListMethodBody(data, ParameterType.Array, parameters)
- .AppendIListMethodBody(data, ParameterType.List, parameters)
- .AppendIListMethodBody(data, ParameterType.Span, parameters)
- .AppendIListMethodBody(data, ParameterType.ReadOnlySpan, parameters)
- .AppendIListMethodBody(data, ParameterType.Enumerable, parameters);
-
- code.AppendEnumerableMethodBody(data, ParameterType.Array, ParameterType.Enumerable, parameters)
- .AppendEnumerableMethodBody(data, ParameterType.List, ParameterType.Enumerable, parameters)
- .AppendEnumerableMethodBody(data, ParameterType.Enumerable, ParameterType.Enumerable, parameters);
-
- return code;
- }
-
- private static CodeWriter AppendArrayMethodBody(
- this CodeWriter code,
- in CreateFromDataSpan data,
- ParameterType fromParameterType,
- in Parameters parameters)
- {
- var fromName = parameters.From;
-
- var capacity = GetLengthType(fromParameterType) switch
- {
- LengthType.None => "0",
- LengthType.Count => $"{fromName}.Count",
- LengthType.Length => $"{fromName}.Length",
- _ => throw new ArgumentOutOfRangeException()
- };
-
- return code
- .AppendMethodDeclaration(data, parameters, fromParameterType, ParameterType.Array)
- .AppendMultiline(
- $$"""
- {
- var __to = new {{data.ToTypeName}}[{{capacity}}];
-
- for (var __i = 0; __i < __to.Length; __i++)
- __to[__i] = {{fromName}}[__i].{{data.MethodName}}({{parameters.EnumParameters}});
-
- return __to;
- }
- """)
- .AppendLine();
- }
-
- private static CodeWriter AppendListMethodBody(
- this CodeWriter code,
- in CreateFromDataSpan data,
- ParameterType fromParameterType,
- in Parameters parameters)
- {
- var capacity = GetLengthType(fromParameterType) switch
- {
- LengthType.None => string.Empty,
- LengthType.Count => $"{parameters.From}.Count",
- LengthType.Length => $"{parameters.From}.Length",
- _ => throw new ArgumentOutOfRangeException()
- };
-
- return code
- .AppendMethodDeclaration(data, parameters, fromParameterType, ParameterType.List)
- .AppendMultiline(
- $$"""
- {
- var __to = new {{List}}<{{data.ToTypeName}}>({{capacity}});
-
- foreach(var __from in {{parameters.From}})
- __to.Add(__from.{{data.MethodName}}({{parameters.EnumParameters}}));
-
- return __to;
- }
- """)
- .AppendLine();
- }
-
- private static CodeWriter AppendIListMethodBody(
- this CodeWriter code,
- in CreateFromDataSpan data,
- ParameterType fromParameterType,
- in Parameters parameters)
- {
- return code
- .AppendMethodDeclaration(data, parameters, fromParameterType, ParameterType.IList)
- .AppendMultiline(
- $$"""
- {
- var __to = __createList();
-
- foreach(var __from in {{parameters.From}})
- __to.Add(__from.{{data.MethodName}}({{parameters.EnumParameters}}));
-
- return __to;
- }
- """)
- .AppendLine();
- }
-
- private static CodeWriter AppendEnumerableMethodBody(
- this CodeWriter code,
- in CreateFromDataSpan data,
- ParameterType fromParameterType,
- ParameterType toParameterType,
- in Parameters parameters)
- {
- return code
- .AppendMethodDeclaration(data, parameters, fromParameterType, toParameterType)
- .AppendMultiline(
- $$"""
- {
- foreach (var __from in {{parameters.From}})
- yield return __from.{{data.MethodName}}({{parameters.EnumParameters}});
- }
- """)
- .AppendLine();
- }
-
- private static CodeWriter AppendMethodDeclaration(
- this CodeWriter code,
- in CreateFromDataSpan data,
- in Parameters parameters,
- ParameterType fromParameterType,
- ParameterType toParameterType)
- {
- var methodName = data.MethodName;
- var returnType = data.ToTypeName;
- var additionalParameter = string.Empty;
-
- switch (toParameterType)
- {
- case ParameterType.None: break;
- case ParameterType.List:
- methodName += "AsList";
- returnType = $"{List}<{returnType}>";
- break;
-
- case ParameterType.Span:
- case ParameterType.Array:
- case ParameterType.ReadOnlySpan:
- methodName += "AsArray";
- returnType += "[]";
- break;
-
- case ParameterType.Enumerable:
- methodName += "AsEnumerable";
- returnType = $"{IEnumerable}<{returnType}>";
- break;
-
- case ParameterType.IList:
- methodName += "AsList";
- returnType = $"{IList}<{returnType}>";
- additionalParameter = $", {Func}<{IList}<{data.ToTypeName}>> __createList";
- break;
-
- default: throw new ArgumentOutOfRangeException(nameof(toParameterType), toParameterType, null);
- }
-
- if (!data.CanBeInherited)
- {
- return code.AppendMultiline(
- $"""
- {GeneratedAttribute}
- public static {returnType} {methodName}({parameters.Method(fromParameterType, data.FromTypeName)}{additionalParameter})
- """);
- }
-
- return code.AppendMultiline(
- $"""
- {GeneratedAttribute}
- public static {returnType} {methodName}({parameters.Method(fromParameterType, "T")}{additionalParameter})
- where T : {data.FromTypeName}
- """);
- }
-
- private static LengthType GetLengthType(ParameterType type) => type switch
- {
- ParameterType.None => LengthType.None,
- ParameterType.Array => LengthType.Length,
- ParameterType.List => LengthType.Count,
- ParameterType.IList => LengthType.Count,
- ParameterType.Span => LengthType.Length,
- ParameterType.ReadOnlySpan => LengthType.Length,
- ParameterType.Enumerable => LengthType.None,
- _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
- };
-
- private static Parameters GetParameters(IMethodSymbol constructor, ITypeSymbol fromType)
- {
- string? fromName = null;
- StringBuilder parameters = new();
- StringBuilder methodParameters = new();
- StringBuilder constructorParameters = new();
-
- foreach (var parameter in constructor.Parameters)
- {
- if (constructorParameters.Length is not 0)
- constructorParameters.Append(", ");
-
- if (fromName is null && Comparer.Equals(parameter.Type, fromType))
- {
- fromName = parameter.Name;
- constructorParameters.Append("{0}");
- }
- else
- {
- if (parameters.Length is not 0)
- parameters.Append(", ");
-
- parameters.Append($"{parameter.Name}");
- methodParameters.Append($", {parameter.Type.ToDisplayStringGlobal()} {parameter.Name}");
- constructorParameters.Append($"{parameter.Name}");
- }
- }
-
- return new Parameters(fromName!, methodParameters, parameters, constructorParameters);
- }
-
- private readonly ref struct Parameters(
- string from,
- StringBuilder method,
- StringBuilder parameters,
- StringBuilder constructor)
- {
- public readonly string From = from;
- public readonly string EnumParameters = parameters.ToString();
-
- private readonly string _methods = from + method;
- private readonly string _constructor = constructor.ToString();
-
-
- public string Method(ParameterType type, string fromType)
- {
- return type switch
- {
- ParameterType.None => $"this {fromType} {_methods}",
- ParameterType.Array => $"this {fromType}[] {_methods}",
- ParameterType.Span => $"this {Span}<{fromType}> {_methods}",
- ParameterType.List => $"this {List}<{fromType}> {_methods}",
- ParameterType.IList => $"this {IList}<{fromType}> {_methods}",
- ParameterType.ReadOnlySpan => $"this {ReadOnlySpan}<{fromType}> {_methods}",
- ParameterType.Enumerable => $"this {IEnumerable}<{fromType}> {_methods}",
- _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
- };
- }
-
- public string Constructor(string fromName) => string.Format(_constructor, fromName);
- }
-
- private enum LengthType
- {
- None,
- Count,
- Length,
- }
-
- private enum ParameterType
- {
- None,
- List,
- IList,
- Array,
- Span,
- ReadOnlySpan,
- Enumerable,
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/CreateFromGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/CreateFromGenerator.cs
deleted file mode 100644
index 3b77551..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/CreateFromGenerator.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System.Linq;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Microsoft.CodeAnalysis.CSharp;
-using System.Runtime.CompilerServices;
-using Aspid.MVVM.Generators.Descriptions;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.CreateFrom.Body;
-using Aspid.MVVM.Generators.CreateFrom.Data;
-
-namespace Aspid.MVVM.Generators.CreateFrom;
-
-[Generator(LanguageNames.CSharp)]
-public class CreateFromGenerator : IIncrementalGenerator
-{
- public void Initialize(IncrementalGeneratorInitializationContext context)
- {
- var provider = context.SyntaxProvider.ForAttributeWithMetadataName(Classes.CreateFromAttribute.FullName, SyntacticPredicate, FindCreateFrom).
- Where(foundForSourceGenerator => foundForSourceGenerator.IsNeed).
- Select((foundForSourceGenerator, _) => foundForSourceGenerator.Container);
-
- context.RegisterSourceOutput(
- source: provider,
- action: GenerateCode);
- }
-
- private static bool SyntacticPredicate(SyntaxNode node, CancellationToken cancellationToken)
- {
- var candidate = node switch
- {
- ConstructorDeclarationSyntax syntax => syntax,
- _ => null
- };
-
- return candidate is not null && !candidate.Modifiers.Any(SyntaxKind.StaticKeyword);
- }
-
- private static FoundForGenerator FindCreateFrom(
- GeneratorAttributeSyntaxContext context,
- CancellationToken cancellationToken)
- {
- if (context.TargetSymbol is not IMethodSymbol constructor) return default;
-
- var attribute = context.Attributes.First(attribute =>
- attribute.AttributeClass?.ToDisplayString() == Classes.CreateFromAttribute.FullName);
-
- if (attribute.ConstructorArguments.First().Value is not ITypeSymbol fromType) return default;
-
- if (constructor.Parameters.Length == 0) return default;
- var candidate = Unsafe.As(context.TargetNode);
- return new FoundForGenerator(new CreateFromData(candidate, constructor, fromType));
- }
-
- private static void GenerateCode(SourceProductionContext context, CreateFromData data)
- {
- var @namespace = data.Declaration.GetNamespaceName();
- var dataSpan = new CreateFromDataSpan(data);
-
- if (data.Declaration.Parent is not TypeDeclarationSyntax typeDeclaration) return;
-
- var i = 0;
- var index = -1;
-
- foreach (var constructor in typeDeclaration.Members.OfType())
- {
- if (constructor == data.Declaration)
- {
- index = i;
- break;
- }
-
- i++;
- }
-
- if (index == -1) return;
-
- var declaration = new DeclarationText(
- "public static",
- "class",
- $"{dataSpan.FromType.ToDisplayString().Replace(".", "_")}To{dataSpan.ToType.ToDisplayString().Replace(".", "_")}_{index}",
- null);
-
- var code = new CodeWriter();
- code.AppendClassBegin(@namespace, declaration)
- .AppendCreateFromBody(dataSpan)
- .AppendClassEnd(@namespace);
-
- context.AddSource(declaration.GetFileName(@namespace, "IViewModel"), code.GetSourceText());
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromData.cs
deleted file mode 100644
index b02b9ab..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromData.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Aspid.MVVM.Generators.CreateFrom.Data;
-
-public readonly struct CreateFromData(
- ConstructorDeclarationSyntax declaration,
- IMethodSymbol constructor,
- ITypeSymbol fromType)
-{
- public readonly ITypeSymbol FromType = fromType;
- public readonly IMethodSymbol Constructor = constructor;
- public readonly ConstructorDeclarationSyntax Declaration = declaration;
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromDataSpan.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromDataSpan.cs
deleted file mode 100644
index 82c5741..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/CreateFrom/Data/CreateFromDataSpan.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.CreateFrom.Data;
-
-public readonly ref struct CreateFromDataSpan(CreateFromData data)
-{
- public readonly CreateFromData Data = data;
- public readonly IMethodSymbol Constructor = data.Constructor;
-
- public readonly ITypeSymbol ToType = data.Constructor.ContainingType;
- public readonly string ToName = data.Declaration.Identifier.Text;
- public readonly string ToTypeName = data.Constructor.ContainingType.ToDisplayStringGlobal();
-
- public readonly ITypeSymbol FromType = data.FromType;
- public readonly string FromTypeName = data.FromType.ToDisplayStringGlobal();
-
- public readonly string MethodName = $"To{data.Declaration.Identifier.Text}";
- public readonly bool CanBeInherited = data.FromType.TypeKind != TypeKind.Struct && !data.FromType.IsSealed;
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.Aspid.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.Aspid.cs
index 4535b0e..b8c58d6 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.Aspid.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.Aspid.cs
@@ -1,23 +1,37 @@
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
-namespace Aspid.MVVM.Generators.Descriptions;
+namespace Aspid.MVVM.Generators.Generators.Descriptions;
// ReSharper disable InconsistentNaming
-public static partial class Classes
+public static class Classes
{
#region Views
public static readonly TypeText IView =
new(nameof(IView), Namespaces.Aspid_MVVM);
public static readonly AttributeText ViewAttribute =
- new("View", Namespaces.Aspid_MVVM);
+ new("ViewAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText AsBinderAttribute =
- new("AsBinder", Namespaces.Aspid_MVVM);
+ new("AsBinderAttribute", Namespaces.Aspid_MVVM);
public static readonly TypeText ViewBinder =
new (nameof(ViewBinder), Namespaces.Aspid_MVVM);
#endregion
+
+ #region Headers
+ public static readonly AttributeText HeaderAttribute =
+ new(nameof(HeaderAttribute), "UnityEngine");
+
+ public static readonly AttributeText HeaderGroupAttribute =
+ new (nameof(HeaderGroupAttribute), Namespaces.Aspid_MVVM);
+
+ public static readonly AttributeText HeaderGroupStartAttribute =
+ new (nameof(HeaderGroupStartAttribute), Namespaces.Aspid_MVVM);
+
+ public static readonly AttributeText HeaderGroupEndAttribute =
+ new (nameof(HeaderGroupEndAttribute), Namespaces.Aspid_MVVM);
+ #endregion
#region Binders
public static readonly TypeText BindMode =
@@ -25,18 +39,21 @@ public static partial class Classes
public static readonly TypeText IBinder =
new(nameof(IBinder), Namespaces.Aspid_MVVM);
-
+
+ public static readonly TypeText IAnyBinder =
+ new(nameof(IAnyBinder), Namespaces.Aspid_MVVM);
+
public static readonly TypeText IReverseBinder =
new(nameof(IReverseBinder), Namespaces.Aspid_MVVM);
public static readonly TypeText MonoBinder =
- new(nameof(MonoBinder), Namespaces.Aspid_MVVM_UNITY);
+ new(nameof(MonoBinder), Namespaces.Aspid_MVVM);
public static readonly AttributeText BinderLogAttribute =
- new("BinderLog", Namespaces.Aspid_MVVM);
+ new("BinderLogAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText RequireBinderAttribute =
- new("RequireBinder", Namespaces.Aspid_MVVM);
+ new("RequireBinderAttribute", Namespaces.Aspid_MVVM);
#endregion
#region View Models
@@ -44,7 +61,7 @@ public static partial class Classes
new(nameof(IViewModel), Namespaces.Aspid_MVVM);
public static readonly AttributeText ViewModelAttribute =
- new("ViewModel", Namespaces.Aspid_MVVM);
+ new("ViewModelAttribute", Namespaces.Aspid_MVVM);
public static readonly TypeText FindBindableMemberResult =
new(nameof(FindBindableMemberResult), Namespaces.Aspid_MVVM);
@@ -55,31 +72,31 @@ public static partial class Classes
#region Bind Attributes
public static readonly AttributeText BindAttribute =
- new("Bind", Namespaces.Aspid_MVVM);
+ new("BindAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText IdAttribute =
- new("BindId", Namespaces.Aspid_MVVM);
+ new("BindIdAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText AccessAttribute =
- new("Access", Namespaces.Aspid_MVVM);
+ new("AccessAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText BindAlsoAttribute =
- new("BindAlso", Namespaces.Aspid_MVVM);
+ new("BindAlsoAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText IgnoreAttribute =
- new("IgnoreBind", Namespaces.Aspid_MVVM);
+ new("IgnoreBindAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText OneWayBindAttribute =
- new("OneWayBind", Namespaces.Aspid_MVVM);
+ new("OneWayBindAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText TwoWayBindAttribute =
- new("TwoWayBind", Namespaces.Aspid_MVVM);
+ new("TwoWayBindAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText OneTimeBindAttribute =
- new("OneTimeBind", Namespaces.Aspid_MVVM);
+ new("OneTimeBindAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText OneWayToSourceBindAttribute =
- new("OneWayToSourceBind", Namespaces.Aspid_MVVM);
+ new("OneWayToSourceBindAttribute", Namespaces.Aspid_MVVM);
#endregion
#region Bindable Member Events
@@ -98,40 +115,40 @@ public static partial class Classes
public static readonly TypeText IBinderRemover =
new(nameof(IBinderRemover), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayBindableMember =
+ public static readonly TypeText OneWayBindableMember =
new(nameof(OneWayBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayStructBindableMember =
+ public static readonly TypeText OneWayStructBindableMember =
new(nameof(OneWayStructBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayEnumBindableMember =
+ public static readonly TypeText OneWayEnumBindableMember =
new(nameof(OneWayEnumBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? TwoWayBindableMember =
+ public static readonly TypeText TwoWayBindableMember =
new(nameof(TwoWayBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? TwoWayStructBindableMember =
+ public static readonly TypeText TwoWayStructBindableMember =
new(nameof(TwoWayStructBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? TwoWayEnumBindableMember =
+ public static readonly TypeText TwoWayEnumBindableMember =
new(nameof(TwoWayEnumBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneTimeBindableMember =
+ public static readonly TypeText OneTimeBindableMember =
new(nameof(OneTimeBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneTimeStructBindableMember =
+ public static readonly TypeText OneTimeStructBindableMember =
new(nameof(OneTimeStructBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneTimeEnumBindableMember =
+ public static readonly TypeText OneTimeEnumBindableMember =
new(nameof(OneTimeEnumBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayToSourceBindableMember =
+ public static readonly TypeText OneWayToSourceBindableMember =
new(nameof(OneWayToSourceBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayToSourceStructBindableMember =
+ public static readonly TypeText OneWayToSourceStructBindableMember =
new(nameof(OneWayToSourceStructBindableMember), Namespaces.Aspid_MVVM);
- public static readonly TypeText? OneWayToSourceEnumBindableMember =
+ public static readonly TypeText OneWayToSourceEnumBindableMember =
new(nameof(OneWayToSourceEnumBindableMember), Namespaces.Aspid_MVVM);
#endregion
@@ -143,7 +160,7 @@ public static partial class Classes
new(nameof(IRelayCommand), Namespaces.Aspid_MVVM);
public static readonly AttributeText RelayCommandAttribute =
- new("RelayCommand", Namespaces.Aspid_MVVM);
+ new("RelayCommandAttribute", Namespaces.Aspid_MVVM);
#endregion
public static readonly TypeText Unsafe =
@@ -153,8 +170,8 @@ public static partial class Classes
new(nameof(Ids), Namespaces.Aspid_MVVM_Generated);
public static readonly AttributeText CreateFromAttribute =
- new("CreateFrom", Namespaces.Aspid_MVVM);
+ new("CreateFromAttribute", Namespaces.Aspid_MVVM);
public static readonly AttributeText AddComponentContextMenuAttribute =
- new ("AddComponentContextMenu", Namespaces.Aspid_MVVM_UNITY);
+ new ("AddComponentContextMenuAttribute", Namespaces.Aspid_MVVM);
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.System.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.System.cs
deleted file mode 100644
index 3a8d0f2..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.System.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.Descriptions;
-
-public static partial class Classes
-{
- public static readonly TypeText Span = new("Span", Namespaces.System);
- public static readonly TypeText ReadOnlySpan = new("ReadOnlySpan", Namespaces.System);
- public static readonly TypeText Func = new("Func", Namespaces.System);
- public static readonly TypeText Action = new("Action", Namespaces.System);
- public static readonly TypeText Delegate = new("Delegate", Namespaces.System);
-
- public static readonly TypeText Exception = new("Exception", Namespaces.System);
- public static readonly TypeText ArgumentNullException = new("ArgumentNullException", Namespaces.System);
- public static readonly TypeText InvalidOperationException = new("InvalidOperationException", Namespaces.System);
-
- public static readonly TypeText List = new("List", Namespaces.System_Collections_Generic);
- public static readonly TypeText IList = new("IList", Namespaces.System_Collections_Generic);
- public static readonly TypeText Dictionary = new("Dictionary", Namespaces.System_Collections_Generic);
- public static readonly TypeText IEnumerable = new("IEnumerable", Namespaces.System_Collections_Generic);
- public static readonly TypeText EqualityComparer = new("EqualityComparer", Namespaces.System_Collections_Generic);
-
- public static readonly TypeText EditorBrowsableState = new(nameof(EditorBrowsableState), Namespaces.System_ComponentModel);
- public static readonly AttributeText EditorBrowsableAttribute = new("EditorBrowsable", Namespaces.System_ComponentModel);
-
- public static readonly TypeText MethodImplOptions = new("MethodImplOptions", Namespaces.System_Runtime_CompilerServices);
- public static readonly AttributeText MethodImplAttribute = new("MethodImpl", Namespaces.System_Runtime_CompilerServices);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.UnityEngine.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.UnityEngine.cs
deleted file mode 100644
index aa04347..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Classes.UnityEngine.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.Descriptions;
-
-public static partial class Classes
-{
- public static readonly TypeText ProfilerMarker = new("ProfilerMarker", Namespaces.Unity_Profiling);
-
- public static readonly TypeText Object = new("Object", Namespaces.UnityEngine);
- public static readonly TypeText Component = new("Component", Namespaces.UnityEngine);
- public static readonly TypeText MonoBehaviour = new("MonoBehaviour", Namespaces.UnityEngine);
- public static readonly TypeText SerializeField = new("SerializeField", Namespaces.UnityEngine);
-
- public static readonly TypeText MenuItem = new("MenuItem", Namespaces.UnityEditor);
- public static readonly TypeText MenuCommand = new("MenuCommand", Namespaces.UnityEditor);
-
- public static readonly TypeText Button = new("Button", Namespaces.UnityEngine_UI);
- public static readonly TypeText Toggle = new("Toggle", Namespaces.UnityEngine_UI);
- public static readonly TypeText Slider = new("Slider", Namespaces.UnityEngine_UI);
- public static readonly TypeText ScrollRect = new("ScrollRect", Namespaces.UnityEngine_UI);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/General.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Constants.cs
similarity index 52%
rename from Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/General.cs
rename to Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Constants.cs
index 7d1aaf3..37b90bf 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/General.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Constants.cs
@@ -1,19 +1,20 @@
-namespace Aspid.MVVM.Generators.Descriptions;
+using static Aspid.Generators.Helper.Classes;
-public class General
+namespace Aspid.MVVM.Generators.Generators.Descriptions;
+
+public static class Constants
{
public const string GeneratedCodeIdAttribute =
- "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.IdGenerator\", \"1.0.0\")]";
+ "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.IdGenerator\", \"1.1.0\")]";
public const string GeneratedCodeViewAttribute =
- "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.ViewGenerator\", \"1.0.0\")]";
+ "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.ViewGenerator\", \"1.1.0\")]";
public const string GeneratedCodeLogBinderAttribute =
- "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.LogBinderGenerator\", \"1.0.0\")]";
-
- public const string GeneratedCodeCreateFromAttribute =
- "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.CreateFromGenerator\", \"1.0.0\")]";
+ "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.LogBinderGenerator\", \"1.1.0\")]";
public const string GeneratedCodeViewModelAttribute =
- "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.ViewModelGenerator\", \"1.0.0\")]";
+ "[global::System.CodeDom.Compiler.GeneratedCode(\"Aspid.MVVM.Generators.ViewModelGenerator\", \"1.1.0\")]";
+
+ public static readonly string EditorBrowsableAttributeNever = $"[{EditorBrowsableAttribute}({EditorBrowsableState}.Never)]";
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.Aspid.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.Aspid.cs
index a15c35a..69ee7e4 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.Aspid.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.Aspid.cs
@@ -1,7 +1,7 @@
-namespace Aspid.MVVM.Generators.Descriptions;
+namespace Aspid.MVVM.Generators.Generators.Descriptions;
// ReSharper disable InconsistentNaming
-public static partial class Defines
+public static class Defines
{
public const string ASPID_MVVM_BINDER_LOG_DISABLED = nameof(ASPID_MVVM_BINDER_LOG_DISABLED);
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.UnityEngine.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.UnityEngine.cs
deleted file mode 100644
index c5601dc..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Defines.UnityEngine.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Aspid.MVVM.Generators.Descriptions;
-
-// ReSharper disable InconsistentNaming
-public static partial class Defines
-{
- public const string UNITY_EDITOR = nameof(UNITY_EDITOR);
-
- public const string UNITY_IOS = nameof(UNITY_IOS);
- public const string UNITY_ANDROID = nameof(UNITY_ANDROID);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.Aspid.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.Aspid.cs
index 345c9f3..44cf406 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.Aspid.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.Aspid.cs
@@ -1,13 +1,12 @@
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
-namespace Aspid.MVVM.Generators.Descriptions;
+namespace Aspid.MVVM.Generators.Generators.Descriptions;
// ReSharper disable InconsistentNaming
-public static partial class Namespaces
+public static class Namespaces
{
public static readonly NamespaceText Aspid = new(nameof(Aspid));
public static readonly NamespaceText Aspid_MVVM = new("MVVM", Aspid);
- public static readonly NamespaceText Aspid_MVVM_UNITY = new("Unity", Aspid_MVVM);
public static readonly NamespaceText Aspid_MVVM_Generated = new("Generated", Aspid_MVVM);
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.System.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.System.cs
deleted file mode 100644
index 44f3571..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.System.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.Descriptions;
-
-// ReSharper disable InconsistentNaming
-public static partial class Namespaces
-{
- public static readonly NamespaceText System = new(nameof(System));
- public static readonly NamespaceText System_Runtime = new("Runtime", System);
- public static readonly NamespaceText System_Collections = new("Collections", System);
- public static readonly NamespaceText System_ComponentModel = new("ComponentModel", System);
- public static readonly NamespaceText System_Collections_Generic = new("Generic", System_Collections);
- public static readonly NamespaceText System_Runtime_CompilerServices = new("CompilerServices", System_Runtime);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.UnityEngine.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.UnityEngine.cs
deleted file mode 100644
index cfd9f33..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Descriptions/Namespaces.UnityEngine.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.Descriptions;
-
-// ReSharper disable InconsistentNaming
-public static partial class Namespaces
-{
- public static readonly NamespaceText Unity = new("Unity");
- public static readonly NamespaceText Unity_Profiling = new("Profiling", Unity);
-
- public static readonly NamespaceText UnityEngine = new("UnityEngine");
- public static readonly NamespaceText UnityEngine_UI = new("UI", UnityEngine);
-
- public static readonly NamespaceText UnityEditor = new("UnityEditor");
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Data/IdData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Data/IdData.cs
index 764e4b7..fd45829 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Data/IdData.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Data/IdData.cs
@@ -1,9 +1,9 @@
using System;
using Microsoft.CodeAnalysis;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.Ids.Extensions;
+using Aspid.MVVM.Generators.Generators.Descriptions;
+using Aspid.MVVM.Generators.Generators.Ids.Extensions;
-namespace Aspid.MVVM.Generators.Ids.Data;
+namespace Aspid.MVVM.Generators.Generators.Ids.Data;
public readonly struct IdData : IEquatable
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Extensions/IdGeneratorExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Extensions/IdGeneratorExtensions.cs
index 06eb234..624595e 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Extensions/IdGeneratorExtensions.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/Extensions/IdGeneratorExtensions.cs
@@ -1,14 +1,15 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Descriptions;
+using Aspid.Generators.Helper;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using SymbolExtensions = Aspid.MVVM.Generators.Helpers.SymbolExtensions;
-namespace Aspid.MVVM.Generators.Ids.Extensions;
+namespace Aspid.MVVM.Generators.Generators.Ids.Extensions;
public static class IdGeneratorExtensions
{
public static string GetId(this ISymbol member, string prefixName = "")
{
- if (!member.HasAnyAttribute(out var attribute, Classes.IdAttribute))
+ if (!member.TryGetAnyAttributeInSelf(out var attribute, Classes.IdAttribute))
return member.GetName(prefixName);
var value = attribute!.ConstructorArguments[0].Value as string;
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Find.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Find.cs
index 7fd4fb5..55c6621 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Find.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Find.cs
@@ -1,26 +1,26 @@
using System.Threading;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
-using Aspid.MVVM.Generators.Descriptions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.Views.Factories;
-using Aspid.MVVM.Generators.ViewModels.Factories;
+using Aspid.MVVM.Generators.Generators.Views.Factories;
+using Aspid.MVVM.Generators.Generators.ViewModels.Factories;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.Ids;
+namespace Aspid.MVVM.Generators.Generators.Ids;
public partial class IdGenerator
{
- private static FoundForGenerator> GetIdsForSourceGeneration(
+ private static HashSet? GetIdsForSourceGeneration(
GeneratorSyntaxContext context, CancellationToken cancellationToken)
{
var syntax = (TypeDeclarationSyntax)context.Node;
- if (context.SemanticModel.GetDeclaredSymbol(syntax) is not { } symbol) return default;
+ if (context.SemanticModel.GetDeclaredSymbol(syntax) is not { } symbol) return null;
var ids = new HashSet();
- if (symbol.HasAnyAttribute(out var attribute, Classes.ViewAttribute, Classes.ViewModelAttribute))
+ if (symbol.TryGetAnyAttributeInSelf(out var attribute, Classes.ViewAttribute, Classes.ViewModelAttribute))
{
var attributeName = attribute!.AttributeClass!.ToDisplayString();
@@ -33,15 +33,13 @@ private static FoundForGenerator> GetIdsForSourceGeneration(
}
else
{
- var members = BindableMembersFactory.Create(symbol);
+ var members = BindableMembersFactory.Create(symbol, syntax, out _);
foreach (var member in members)
ids.Add(member.Id.SourceValue);
}
}
- return ids.Count is 0
- ? default
- : new FoundForGenerator>(ids);
+ return ids.Count is 0 ? null : ids;
}
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Generate.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Generate.cs
index 7daf40f..ed41e0d 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Generate.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.Generate.cs
@@ -1,10 +1,10 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
-using static Aspid.MVVM.Generators.Descriptions.General;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
-namespace Aspid.MVVM.Generators.Ids;
+namespace Aspid.MVVM.Generators.Generators.Ids;
public partial class IdGenerator
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.cs
index 4a768c4..2f71648 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Ids/IdGenerator.cs
@@ -3,16 +3,17 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-namespace Aspid.MVVM.Generators.Ids;
+namespace Aspid.MVVM.Generators.Generators.Ids;
[Generator(LanguageNames.CSharp)]
public partial class IdGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+ // ReSharper disable once NullableWarningSuppressionIsUsed
var provider = context.SyntaxProvider.CreateSyntaxProvider(SyntacticPredicate, GetIdsForSourceGeneration)
- .Where(foundFor => foundFor.IsNeed)
- .Select((foundFor, _) => foundFor.Container);
+ .Where(foundFor => foundFor is not null)
+ .Select((foundFor, _) => foundFor!);
context.RegisterSourceOutput(provider.Collect(), GenerateCode);
}
@@ -21,7 +22,7 @@ private static bool SyntacticPredicate(SyntaxNode node, CancellationToken cancel
{
var candidate = node switch
{
- ClassDeclarationSyntax or StructDeclarationSyntax => node as TypeDeclarationSyntax,
+ ClassDeclarationSyntax => node as TypeDeclarationSyntax,
_ => null
};
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembersBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableInterfaceMembersBody.cs
similarity index 65%
rename from Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembersBody.cs
rename to Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableInterfaceMembersBody.cs
index 3e7af2e..32b4766 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembersBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableInterfaceMembersBody.cs
@@ -1,26 +1,26 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.ViewModels.Data;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using static Aspid.MVVM.Generators.Descriptions.General;
-using BindMode = Aspid.MVVM.Generators.ViewModels.Data.BindMode;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+using BindMode = Aspid.MVVM.Generators.Generators.ViewModels.Data.BindMode;
-namespace Aspid.MVVM.Generators.ViewModels.Body;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
-public static class BindableMembersBody
+public static class BindableInterfaceMembersBody
{
public static void Generate(
string @namespace,
in ViewModelData data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
var code = new CodeWriter();
- code.AppendClassBegin(@namespace, declaration)
+ code.BeginClass(@namespace, declaration)
.AppendProperties(data)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
- context.AddSource(declaration.GetFileName(@namespace, "BindableMembers"), code.GetSourceText());
+ context.AddSource(declaration.GetFileName(@namespace, "BindableInterfaceMembers"), code.GetSourceText());
}
private static CodeWriter AppendProperties(this CodeWriter code, in ViewModelData data)
@@ -39,7 +39,7 @@ private static CodeWriter AppendProperties(this CodeWriter code, in ViewModelDat
if (!propertyType.Contains(IReadOnlyValueBindableMember))
{
- if (!member.BindableMemberPropertyType.Contains(IReadOnlyBindableMember))
+ if (!member.Bindable.PropertyType.Contains(IReadOnlyBindableMember))
continue;
}
}
@@ -47,7 +47,7 @@ private static CodeWriter AppendProperties(this CodeWriter code, in ViewModelDat
var interfaceType = customInterface.Interface.ToDisplayStringGlobal();
code.AppendLine(GeneratedCodeViewModelAttribute)
- .AppendLine($"{propertyType} {interfaceType}.{property.Name} => {member.GeneratedName}Bindable;")
+ .AppendLine($"{propertyType} {interfaceType}.{property.Name} => {member.Bindable.PropertyName};")
.AppendLine();
}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembers.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembers.cs
new file mode 100644
index 0000000..4f59f5c
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/BindableMembers.cs
@@ -0,0 +1,157 @@
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using System.Collections.Generic;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+using SymbolExtensions = Aspid.MVVM.Generators.Helpers.SymbolExtensions;
+using BindMode = Aspid.MVVM.Generators.Generators.ViewModels.Data.BindMode;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
+
+public static class BindableMembers
+{
+ public static void Generate(
+ string @namespace,
+ in ViewModelData data,
+ DeclarationText declaration,
+ in SourceProductionContext context)
+ {
+ var code = new CodeWriter();
+
+ code.BeginClass(@namespace, declaration)
+ .AppendBody(data)
+ .EndClass(@namespace);
+
+ context.AddSource(declaration.GetFileName(@namespace, "BindableMembers"), code.GetSourceText());
+ }
+
+ private static IEnumerable GetBindableBindAlso(ISymbol member, in ViewModelData data)
+ {
+ var set = new HashSet();
+
+ foreach (var attribute in member.GetAttributes())
+ {
+ if (attribute.AttributeClass is not null &&
+ attribute.AttributeClass.ToDisplayStringGlobal() == BindAlsoAttribute)
+ {
+ var value = attribute.ConstructorArguments[0].Value;
+ if (value is null) continue;
+
+ set.Add(value.ToString());
+ }
+ }
+
+ return data.Members.Where(bindAlso =>
+ set.Contains(bindAlso.Name) && bindAlso.Mode is not BindMode.OneTime and not BindMode.None);
+ }
+
+ extension(CodeWriter code)
+ {
+ private CodeWriter AppendBody(in ViewModelData data)
+ {
+ if (!data.Members.IsEmpty)
+ {
+ code.AppendBindableMembers(data);
+ }
+
+ return code
+ .AppendNotifyAll(data)
+ .AppendLine()
+ .AppendNotifyCanExecuteChangedAll(data);
+ }
+
+ private CodeWriter AppendBindableMembers(in ViewModelData data)
+ {
+ foreach (var member in data.Members)
+ {
+ var capitalizeName = member.Name.CapitalizeFirstLetter();
+
+ code.AppendLine($"#region {capitalizeName}")
+ .AppendMultiline(member.Bindable.Declaration)
+ .AppendLine();
+
+ if (!string.IsNullOrWhiteSpace(member.Bindable.OnPropertyChangedName))
+ {
+ code.AppendLine($"{GeneratedCodeViewModelAttribute}")
+ .AppendLine($"private void On{capitalizeName}PropertyChanged()")
+ .BeginBlock()
+ .AppendLineIf(!string.IsNullOrWhiteSpace(member.Bindable.Invoke), member.Bindable.Invoke);
+
+ foreach (var bindAlso in GetBindableBindAlso(member.Member, data))
+ {
+ code.AppendLineIf(!string.IsNullOrWhiteSpace(member.Bindable.OnPropertyChangedName), $"{bindAlso.Bindable.OnPropertyChangedName}();");
+ }
+
+ code.EndBlock();
+ }
+
+ code.AppendLine("#endregion")
+ .AppendLine();
+ }
+
+ return code;
+ }
+
+ private CodeWriter AppendNotifyAll(in ViewModelData data)
+ {
+ var modifiers = "public";
+ if (data.Inheritor is not Inheritor.None) modifiers += " override";
+ else if (!data.Symbol.IsSealed) modifiers += " virtual";
+
+ code.AppendLine(GeneratedCodeViewModelAttribute)
+ .AppendLine($"{modifiers} void NotifyAll()")
+ .BeginBlock()
+ .AppendLineIf(data.Inheritor is Inheritor.Inheritor, "base.NotifyAll();");
+
+ foreach (var member in data.Members)
+ {
+ var invoke = member.Bindable.Invoke;
+ code.AppendLineIf(!string.IsNullOrWhiteSpace(invoke), invoke);
+ }
+
+ return code.EndBlock();
+ }
+
+ private CodeWriter AppendNotifyCanExecuteChangedAll(in ViewModelData data)
+ {
+ var modifiers = "public";
+ if (data.Inheritor is not Inheritor.None) modifiers += " override";
+ else if (!data.Symbol.IsSealed) modifiers += " virtual";
+
+ code.AppendLine(GeneratedCodeViewModelAttribute)
+ .AppendLine($"{modifiers} void NotifyCanExecuteChangedAll()")
+ .BeginBlock()
+ .AppendLineIf(data.Inheritor is Inheritor.Inheritor, "base.NotifyCanExecuteChangedAll();");
+
+ foreach (var member in data.Members)
+ {
+ var name = member.Name;
+
+ if (member is BindableCommandInfo command)
+ {
+ if (string.IsNullOrWhiteSpace(command.CanExecute)) continue;
+ name = $"{SymbolExtensions.GetFieldName(name, prefix: "__")}";
+ }
+ else
+ {
+ var memberType = member.Member.GetSymbolType();
+ if (memberType is null) continue;
+
+ if (!memberType.ToDisplayStringGlobal().Contains(IRelayCommand))
+ {
+ if (!memberType.AllInterfaces.Any(i => i.ToDisplayStringGlobal().Contains(IRelayCommand)))
+ continue;
+ }
+ }
+
+ code.AppendLine($"{name}?.NotifyCanExecuteChanged();");
+ }
+
+ return code.EndBlock();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/FindBindableMembersBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/FindBindableMembersBody.cs
index 0e73bbd..0705266 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/FindBindableMembersBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/FindBindableMembersBody.cs
@@ -1,29 +1,30 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
-using Aspid.MVVM.Generators.ViewModels.Data;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using static Aspid.MVVM.Generators.Descriptions.Defines;
-using static Aspid.MVVM.Generators.Descriptions.General;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using static Aspid.Generators.Helper.Unity.UnityClasses;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Defines;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
-namespace Aspid.MVVM.Generators.ViewModels.Body;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
public static class FindBindableMembersBody
{
public static void Generate(
string @namespace,
in ViewModelData data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
string[] baseTypes = [IViewModel];
var code = new CodeWriter();
- code.AppendClassBegin(@namespace, declaration, baseTypes)
+ code.BeginClass(@namespace, declaration, baseTypes)
.AppendBody(data)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
context.AddSource(declaration.GetFileName(@namespace, "FindBindableMembers"), code.GetSourceText());
}
@@ -43,8 +44,8 @@ private static CodeWriter AppendMarkers(this CodeWriter code, in ViewModelData d
return code.AppendMultiline(
$"""
#if !{ASPID_MVVM_UNITY_PROFILER_DISABLED}
+ {EditorBrowsableAttributeNever}
{GeneratedCodeViewModelAttribute}
- [{EditorBrowsableAttribute}({EditorBrowsableState}.Never)]
private static readonly {ProfilerMarker} __findBindableMemberMarker = new("{className}.FindBindableMember");
#endif
""");
@@ -52,7 +53,7 @@ private static CodeWriter AppendMarkers(this CodeWriter code, in ViewModelData d
private static CodeWriter AppendFindBindableMember(this CodeWriter code, in ViewModelData data)
{
- var addedMembers = new HashSet();
+ var addedMembers = new HashSet();
var modifiers = "public";
if (data.Inheritor is not Inheritor.None) modifiers = "public override";
@@ -117,7 +118,7 @@ private static CodeWriter AppendFindBindableMember(this CodeWriter code, in View
return code;
- void AppendIdBlock(ImmutableArray members)
+ void AppendIdBlock(ImmutableArray members)
{
foreach (var member in members)
{
@@ -127,7 +128,7 @@ void AppendIdBlock(ImmutableArray members)
$$"""
case {{member.Id}}:
{
- return new({{member.GeneratedName}}Bindable);
+ return new({{member.Bindable.PropertyName}});
}
""");
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertiesBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertiesBody.cs
new file mode 100644
index 0000000..a31b510
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertiesBody.cs
@@ -0,0 +1,41 @@
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using System.Collections.Immutable;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
+
+public static class GeneratedPropertiesBody
+{
+ public static void Generate(
+ string namespaceName,
+ in ViewModelData data,
+ DeclarationText declaration,
+ in SourceProductionContext context)
+ {
+ var fields = data.Members.OfType().ToImmutableArray();
+ if (fields.Length is 0) return;
+
+ var code = new CodeWriter();
+
+ code.BeginClass(namespaceName, declaration)
+ .AppendBody(fields)
+ .EndClass(namespaceName);
+
+ context.AddSource(declaration.GetFileName(namespaceName, "GeneratedProperties"), code.GetSourceText());
+ }
+
+ extension(CodeWriter code)
+ {
+ private CodeWriter AppendBody(in ImmutableArray fields)
+ {
+ foreach (var field in fields)
+ {
+ code.AppendMultiline(field.Declaration);
+ }
+
+ return code;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertyMethodsBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertyMethodsBody.cs
new file mode 100644
index 0000000..f41063e
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/GeneratedPropertyMethodsBody.cs
@@ -0,0 +1,41 @@
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using System.Collections.Immutable;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
+
+public static class GeneratedPropertyMethodsBody
+{
+ public static void Generate(
+ string namespaceName,
+ in ViewModelData data,
+ DeclarationText declaration,
+ in SourceProductionContext context)
+ {
+ var properties = data.Members.OfType().ToImmutableArray();
+ if (properties.Length is 0) return;
+
+ var code = new CodeWriter();
+
+ code.BeginClass(namespaceName, declaration)
+ .AppendBody(properties)
+ .EndClass(namespaceName);
+
+ context.AddSource(declaration.GetFileName(namespaceName, "GeneratedPropertyMethods"), code.GetSourceText());
+ }
+
+ extension(CodeWriter code)
+ {
+ private CodeWriter AppendBody(in ImmutableArray properties)
+ {
+ foreach (var property in properties)
+ {
+ code.AppendMultiline(property.Declaration);
+ }
+
+ return code;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertiesBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertiesBody.cs
deleted file mode 100644
index 4187432..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertiesBody.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.ViewModels.Data;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.General;
-
-namespace Aspid.MVVM.Generators.ViewModels.Body;
-
-public static class PropertiesBody
-{
- public static void Generate(
- string @namespace,
- in ViewModelData data,
- in DeclarationText declaration,
- in SourceProductionContext context)
- {
- var code = new CodeWriter();
-
- code.AppendClassBegin(@namespace, declaration)
- .AppendBody(data)
- .AppendClassEnd(@namespace);
-
- context.AddSource(declaration.GetFileName(@namespace, "Properties"), code.GetSourceText());
- }
-
- private static CodeWriter AppendBody(this CodeWriter code, in ViewModelData data)
- {
- if (!data.Members.IsEmpty)
- {
- code.AppendFieldEvents(data)
- .AppendProperties(data)
- .AppendBindableMembers(data)
- .AppendSetMethods(data);
- }
-
- return code.AppendNotifyAll(data);
- }
-
- private static CodeWriter AppendBindableMembers(this CodeWriter code, in ViewModelData data)
- {
- foreach (var member in data.Members)
- {
- code.AppendMultiline(member.ToBindableMemberPropertyDeclarationString())
- .AppendLine();
- }
-
- return code;
- }
-
- private static CodeWriter AppendFieldEvents(this CodeWriter code, in ViewModelData data)
- {
- foreach (var member in data.Members)
- {
- var fieldDeclaration = member.ToBindableMemberFieldDeclarationString();
- if (fieldDeclaration is null) continue;
-
- code.AppendMultiline(fieldDeclaration)
- .AppendLine();
- }
-
- return code;
- }
-
- private static CodeWriter AppendProperties(this CodeWriter code, in ViewModelData data)
- {
- foreach (var field in data.Members.OfType())
- {
- if (field.Member.IsConst) continue;
-
- code.AppendMultiline(field.ToDeclarationPropertyString())
- .AppendLine();
- }
-
- return code;
- }
-
- private static CodeWriter AppendSetMethods(this CodeWriter code, in ViewModelData data)
- {
- foreach (var field in data.Members.OfType())
- {
- if (field.Mode is BindMode.OneTime) continue;
-
- code.AppendMultiline(field.ToSetMethodString())
- .AppendLine();
- }
-
- return code;
- }
-
- private static CodeWriter AppendNotifyAll(this CodeWriter code, in ViewModelData data)
- {
- var modifiers = "private";
- if (data.Inheritor is not Inheritor.None) modifiers = "protected override";
- else if (!data.Symbol.IsSealed) modifiers = "protected virtual";
-
- code.AppendLine(GeneratedCodeViewModelAttribute)
- .AppendLine($"{modifiers} void NotifyAll()")
- .BeginBlock()
- .AppendLineIf(data.Inheritor is Inheritor.Inheritor, "base.NotifyAll();");
-
- foreach (var member in data.Members)
- {
- var invoke = member.ToInvokeBindableMemberString();
- code.AppendLineIf(!string.IsNullOrWhiteSpace(invoke), invoke);
- }
-
- return code.EndBlock();
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertyNotificationBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertyNotificationBody.cs
new file mode 100644
index 0000000..a80c4f7
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/PropertyNotificationBody.cs
@@ -0,0 +1,138 @@
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
+
+public static class PropertyNotificationBody
+{
+ public static void Generate(
+ string namespaceName,
+ in ViewModelData data,
+ DeclarationText declaration,
+ in SourceProductionContext context)
+ {
+ var code = new CodeWriter();
+
+ code.BeginClass(namespaceName, declaration)
+ .AppendBody(data)
+ .EndClass(namespaceName);
+
+ context.AddSource(declaration.GetFileName(namespaceName, postfix: "PropertyNotification"), code.GetSourceText());
+ }
+
+ extension(CodeWriter code)
+ {
+ private CodeWriter AppendBody(in ViewModelData data)
+ {
+ return code
+ .AppendOnPropertyChanged(data)
+ .AppendLine()
+ .AppendSetField(data);
+ }
+
+ private CodeWriter AppendOnPropertyChanged(in ViewModelData data)
+ {
+ var notificationData = data.PropertyNotificationData;
+
+ code.AppendLine("#region OnPropertyChanged");
+
+ code.AppendLine(GeneratedCodeViewModelAttribute)
+ .AppendLine($"private void OnPropertyChanged([{CallerLineNumberAttribute}] int line = -1)")
+ .BeginBlock();
+
+ if (notificationData.HasOnPropertyChangedCalls)
+ {
+ var first = true;
+
+ foreach (var kvp in notificationData.OnPropertyChangedCalls)
+ {
+ var propertyName = kvp.Key;
+ var lines = kvp.Value;
+ var linesPattern = string.Join(" or ", lines.Select(line => line.ToString()));
+ var keyword = first ? "if" : "else if";
+
+ first = false;
+ code.AppendLine($"{keyword} (line is {linesPattern}) On{propertyName.CapitalizeFirstLetter()}PropertyChanged();");
+ }
+
+ code.AppendLine($"else throw new {NotImplementedException}($\"OnPropertyChanged: No property found for line {{line}}\");");
+ }
+ else
+ {
+ code.AppendLine($"throw new {NotImplementedException}($\"OnPropertyChanged: No property found for line {{line}}\");");
+ }
+
+ code.EndBlock()
+ .AppendLine();
+
+ code.AppendMultiline(
+ $"""
+ {GeneratedCodeViewModelAttribute}
+ private void OnPropertyChanged(string propertyName, [{CallerLineNumberAttribute}] int line = -1) =>
+ OnPropertyChanged(line);
+ """)
+ .AppendLine("#endregion");
+
+ return code;
+ }
+
+ private CodeWriter AppendSetField(in ViewModelData data)
+ {
+ var notificationData = data.PropertyNotificationData;
+
+ code.AppendLine("#region SetField")
+ .AppendMultiline(
+ $$"""
+ {{GeneratedCodeViewModelAttribute}}
+ private bool SetField(ref T field, T newValue, [{{CallerLineNumberAttribute}}] int line = -1) =>
+ throw new {{NotImplementedException}}("SetField: No property found for line {line}. Use typed overload.");
+
+ {{GeneratedCodeViewModelAttribute}}
+ private bool SetField(ref T field, T newValue, string propertyName, [{{CallerLineNumberAttribute}}] int line = -1) =>
+ throw new {{NotImplementedException}}($"SetField: No property {propertyName} found for line {line}. Use typed overload.");
+ """);
+
+ if (notificationData.HasSetFieldCalls)
+ {
+ foreach (var typeGroup in notificationData.SetFieldCallsByType)
+ {
+ var type = typeGroup.Key;
+ var propertyCalls = typeGroup.Value;
+
+ code.AppendLine(GeneratedCodeViewModelAttribute)
+ .AppendLine($"private bool SetField(ref {type} field, {type} newValue, [{CallerLineNumberAttribute}] int line = -1)")
+ .BeginBlock();
+
+ var first = true;
+ foreach (var kvp in propertyCalls)
+ {
+ var propertyName = kvp.Key;
+ var lines = kvp.Value;
+ var linesPattern = string.Join(" or ", lines.Select(l => l.ToString()));
+ var keyword = first ? "if" : "else if";
+ first = false;
+
+ code.AppendLine($"{keyword} (line is {linesPattern}) return Set{propertyName.CapitalizeFirstLetter()}Field(ref field, newValue);");
+ }
+
+ code.AppendLine($"else throw new {NotImplementedException}($\"SetField: No property found for line {{line}}\");")
+ .EndBlock()
+ .AppendLine()
+ .AppendMultiline(
+ $"""
+ {GeneratedCodeViewModelAttribute}
+ private bool SetField(ref {type} field, {type} newValue, string propertyName, [{CallerLineNumberAttribute}] int line = -1) =>
+ SetField(ref field, newValue, line);
+ """);
+ }
+ }
+
+ return code.AppendLine("#endregion");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/RelayCommandBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/RelayCommandBody.cs
index a5b134d..02400e8 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/RelayCommandBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Body/RelayCommandBody.cs
@@ -1,35 +1,35 @@
using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.ViewModels.Data;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
-namespace Aspid.MVVM.Generators.ViewModels.Body;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Body;
public static class RelayCommandBody
{
public static void Generate(
string @namespace,
in ViewModelData data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
- if (!data.Members.OfType().Any()) return;
+ if (!data.Members.OfType().Any()) return;
var code = new CodeWriter();
- code.AppendClassBegin(@namespace, declaration)
+ code.BeginClass(@namespace, declaration)
.AppendBody(data)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
context.AddSource(declaration.GetFileName(@namespace, "Commands"), code.GetSourceText());
}
private static CodeWriter AppendBody(this CodeWriter code, in ViewModelData data)
{
- foreach (var command in data.Members.OfType())
+ foreach (var command in data.Members.OfType())
{
- code.AppendMultiline(command.ToDeclarationCommandString())
+ code.AppendMultiline(command.CommandDeclaration)
.AppendLine();
}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/BindMode.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/BindMode.cs
index 344db09..af1f4e0 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/BindMode.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/BindMode.cs
@@ -1,4 +1,4 @@
-namespace Aspid.MVVM.Generators.ViewModels.Data;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data;
public enum BindMode
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableBindAlsoInfo.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableBindAlsoInfo.cs
new file mode 100644
index 0000000..e1ee6d9
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableBindAlsoInfo.cs
@@ -0,0 +1,40 @@
+using System;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public sealed class BindableBindAlsoInfo(IPropertySymbol propertySymbol) : IBindableMemberInfo, IEquatable
+{
+ private readonly IPropertySymbol _propertySymbol = propertySymbol;
+
+ public ISymbol Member { get; } = propertySymbol;
+
+ public string Type { get; } = propertySymbol.Type.ToDisplayStringGlobal();
+
+ public string Name { get; } = propertySymbol.Name;
+
+ public IdData Id { get; } = new(propertySymbol);
+
+ public BindMode Mode => BindMode.OneWay;
+
+ public bool HasBindAttribute { get; } = propertySymbol.HasAnyAttributeInSelf(
+ BindAttribute,
+ OneWayBindAttribute,
+ TwoWayBindAttribute,
+ OneTimeBindAttribute,
+ OneWayToSourceBindAttribute);
+
+ public GeneratedBindableMembers Bindable { get; } = GeneratedBindableMembers.CreateForBindAlso(propertySymbol);
+
+ public override bool Equals(object? obj) =>
+ obj is BindableBindAlsoInfo other && Equals(other);
+
+ public bool Equals(BindableBindAlsoInfo other) =>
+ SymbolEqualityComparer.Default.Equals(_propertySymbol, other._propertySymbol);
+
+ public override int GetHashCode() =>
+ SymbolEqualityComparer.Default.GetHashCode(_propertySymbol);
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableCommandInfo.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableCommandInfo.cs
new file mode 100644
index 0000000..ad02fed
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableCommandInfo.cs
@@ -0,0 +1,92 @@
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public sealed class BindableCommandInfo : IBindableMemberInfo
+{
+ public ISymbol Member { get; }
+
+ public string Type { get; }
+
+ public string Name { get; }
+
+ public string CanExecute { get; }
+
+ public IdData Id { get; }
+
+ public BindMode Mode => BindMode.OneTime;
+
+ public GeneratedBindableMembers Bindable { get; }
+
+ public string CommandDeclaration { get; }
+
+ public BindableCommandInfo(IMethodSymbol methodSymbol, string? canExecute, bool isLambda, bool isMethod)
+ {
+ Member = methodSymbol;
+ Type = GetTypeName(methodSymbol);
+ Id = new IdData(methodSymbol, "Command");
+ Name = $"{methodSymbol.GetPropertyName()}Command";
+ Bindable = GeneratedBindableMembers.CreateForRelayCommand(Type, Name);
+
+ var fieldName = $"{methodSymbol.GetFieldName("__")}Command";
+ CanExecute = GetCanExecuteAction(methodSymbol, isLambda, isMethod, canExecute);
+
+ CommandDeclaration =
+ $"""
+ #region {Name}
+ {EditorBrowsableAttributeNever}
+ {GeneratedCodeViewModelAttribute}
+ private {Type} {fieldName};
+
+ {GeneratedCodeViewModelAttribute}
+ private {Type} {Name} => {fieldName} ??= new {Type}({methodSymbol.Name}{CanExecute});
+ #endregion
+ """;
+ }
+
+ private static string GetTypeName(IMethodSymbol command)
+ {
+ var type = new StringBuilder(RelayCommand);
+ var parameters = command.Parameters;
+ if (parameters.Length <= 0) return type.ToString();
+
+ type.Append("<");
+
+ foreach (var parameter in parameters)
+ type.Append($"{parameter.Type.ToDisplayStringGlobal()},");
+
+ type.Length--;
+ type.Append(">");
+
+ return type.ToString();
+ }
+
+ private static string GetCanExecuteAction(IMethodSymbol command, bool isLambda, bool isMethod, string? canExecute)
+ {
+ if (canExecute is null || string.IsNullOrWhiteSpace(canExecute)) return string.Empty;
+
+ var canExecuteName = new StringBuilder(canExecute);
+
+ if (!isLambda)
+ {
+ canExecuteName.Insert(0, ", ");
+ }
+ else
+ {
+ var parameters = command.Parameters;
+ var missingParameters = string.Join(", ", Enumerable.Repeat("_", parameters.Length));
+
+ canExecuteName.Insert(0, $", ({missingParameters}) => ");
+ if (isLambda && isMethod) canExecuteName.Append("()");
+ }
+
+ return canExecuteName.ToString();
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableFieldInfo.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableFieldInfo.cs
new file mode 100644
index 0000000..35c4add
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindableFieldInfo.cs
@@ -0,0 +1,202 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Microsoft.CodeAnalysis.CSharp;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public sealed class BindableFieldInfo : IBindableMemberInfo
+{
+ public ISymbol Member { get; }
+
+ public string Type { get; }
+
+ public string Name { get; }
+
+ public IdData Id { get; }
+
+ public BindMode Mode { get; }
+
+ public GeneratedBindableMembers Bindable { get; }
+
+ public string Declaration { get; }
+
+ public BindableFieldInfo(IFieldSymbol fieldSymbol, BindMode mode)
+ {
+ Mode = mode;
+ Member = fieldSymbol;
+ Id = new IdData(fieldSymbol);
+ Type = fieldSymbol.Type.ToDisplayStringGlobal();
+ Name = fieldSymbol.IsConst ? fieldSymbol.Name : fieldSymbol.GetPropertyName();
+ Bindable = GeneratedBindableMembers.CreateForField(fieldSymbol);
+ var accessors = Accessors.GetAccessors(fieldSymbol);
+
+ var setMethodName = $"Set{Name}";
+ StringBuilder declaration = new();
+
+ if (!fieldSymbol.IsConst)
+ {
+ declaration.AppendLine($"#region {Name}");
+
+ var keywordThis = !fieldSymbol.IsStatic ? "this." : string.Empty;
+ var fieldInvoke = $"{keywordThis}{fieldSymbol.Name}";
+
+ declaration.AppendLine(Mode is BindMode.OneTime
+ ? $"""
+ {GeneratedCodeViewModelAttribute}
+ {accessors.General}{Type} {Name} => {fieldInvoke};
+ """
+ : $$"""
+ {{GeneratedCodeViewModelAttribute}}
+ {{accessors.General}}{{Type}} {{Name}}
+ {
+ {{accessors.Get}}get => {{fieldInvoke}};
+ {{accessors.Set}}set => {{setMethodName}}(value);
+ }
+ """);
+
+ if (Mode is not BindMode.OneTime && Mode is not BindMode.None)
+ {
+ var onChangedMethod = $"On{Name}Changed";
+ var onChangingMethod = $"On{Name}Changing";
+ var methodModifier = Accessors.ConvertAccessorToString(accessors.SetKind);
+
+ var invoke = !string.IsNullOrWhiteSpace(Bindable.OnPropertyChangedName)
+ ? $"{Bindable.OnPropertyChangedName}();"
+ : string.Empty;
+
+ declaration.AppendLine();
+ declaration.AppendLine(
+ $$"""
+ {{GeneratedCodeViewModelAttribute}}
+ {{methodModifier}}void {{setMethodName}}({{Type}} value)
+ {
+ if ({{EqualityComparer_1}}<{{Type}}>.Default.Equals({{fieldInvoke}}, value)) return;
+
+ {{Type}} oldValue = {{fieldInvoke}};
+
+ {{onChangingMethod}}(value);
+ {{onChangingMethod}}(oldValue, value);
+ {
+ {{fieldInvoke}} = value;
+ {{invoke}}
+ }
+ {{onChangedMethod}}(value);
+ {{onChangedMethod}}(oldValue, value);
+ }
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangingMethod}}({{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangingMethod}}({{Type}} oldValue, {{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangedMethod}}({{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangedMethod}}({{Type}} oldValue, {{Type}} newValue);
+ """);
+ }
+
+ declaration.AppendLine("#endregion");
+ }
+
+ Declaration = declaration.ToString();
+ }
+
+ private readonly ref struct Accessors
+ {
+ public readonly SyntaxKind GetKind;
+ public readonly SyntaxKind SetKind;
+
+ public readonly string Get;
+ public readonly string Set;
+ public readonly string General;
+
+ private Accessors(SyntaxKind get, SyntaxKind set)
+ {
+ GetKind = get;
+ SetKind = set;
+
+ switch (Compare(get, set))
+ {
+ case 0:
+ Get = string.Empty;
+ Set = string.Empty;
+ General = ConvertAccessorToString(get);
+ break;
+
+ case > 0:
+ Get = string.Empty;
+ Set = ConvertAccessorToString(set);
+ General = ConvertAccessorToString(get);
+ break;
+
+ case < 0:
+ Get = ConvertAccessorToString(get);
+ Set = string.Empty;
+ General = ConvertAccessorToString(set);
+ break;
+ }
+ }
+
+ public static Accessors GetAccessors(IFieldSymbol field)
+ {
+ var get = SyntaxKind.PrivateKeyword;
+ var set = SyntaxKind.PrivateKeyword;
+
+ if (field.TryGetAnyAttributeInSelf(out var accessAttribute, AccessAttribute))
+ {
+ if (accessAttribute.ConstructorArguments.Length == 1)
+ {
+ var value = (SyntaxKind)(int)(accessAttribute.ConstructorArguments[0].Value ?? SyntaxKind.PrivateKeyword);
+ get = value;
+ set = value;
+ }
+
+ foreach (var argument in accessAttribute!.NamedArguments)
+ {
+ switch (argument.Key)
+ {
+ case "Get": get = (SyntaxKind)(int)(argument.Value.Value ?? SyntaxKind.PrivateKeyword); break;
+ case "Set": set = (SyntaxKind)(int)(argument.Value.Value ?? SyntaxKind.PrivateKeyword); break;
+ }
+ }
+ }
+
+ return new Accessors(get, set);
+ }
+
+ public static string ConvertAccessorToString(SyntaxKind syntaxKind) => syntaxKind switch
+ {
+ SyntaxKind.PublicKeyword => "public ",
+ SyntaxKind.PrivateKeyword => "private ",
+ SyntaxKind.ProtectedKeyword => "protected ",
+ _ => string.Empty
+ };
+
+ private static int Compare(in SyntaxKind get, in SyntaxKind set)
+ {
+ if (get == set) return 0;
+
+ if (set is SyntaxKind.PrivateKeyword) return 1;
+ if (get is SyntaxKind.PrivateKeyword) return -1;
+
+ if (set is SyntaxKind.ProtectedKeyword) return 1;
+ if (get is SyntaxKind.ProtectedKeyword) return -1;
+
+ // This is not impossible.
+ return 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindablePropertyInfo.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindablePropertyInfo.cs
new file mode 100644
index 0000000..c26e0ef
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/BindablePropertyInfo.cs
@@ -0,0 +1,106 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public sealed class BindablePropertyInfo : IBindableMemberInfo
+{
+ public ISymbol Member { get; }
+
+ public string Type { get; }
+
+ public string Name { get; }
+
+ public IdData Id { get; }
+
+ public BindMode Mode { get; }
+
+ public GeneratedBindableMembers Bindable { get; }
+
+ public string Declaration { get; }
+
+ public BindablePropertyInfo(IPropertySymbol propertySymbol, BindMode mode, bool isSetMethodUsed)
+ {
+ Mode = mode;
+ Member = propertySymbol;
+ Id = new IdData(propertySymbol);
+ Name = propertySymbol.Name.CapitalizeFirstLetter();
+ Type = propertySymbol.Type.ToDisplayStringGlobal();
+ Bindable = GeneratedBindableMembers.CreateForProperty(propertySymbol);
+
+ var setMethodName = $"Set{Name}Field";
+ StringBuilder declaration = new();
+
+ if (Mode is not BindMode.OneTime && Mode is not BindMode.None)
+ {
+ var onPropertyChangedMethod = $"On{Name}PropertyChanged";
+
+ if (propertySymbol is { IsReadOnly: false, IsWriteOnly: false })
+ {
+ declaration.AppendLine($"#region {Name}");
+
+ if (isSetMethodUsed)
+ {
+ var onChangedMethod = $"On{Name}Changed";
+ var onChangingMethod = $"On{Name}Changing";
+
+ declaration.AppendLine(
+ $$"""
+ {{GeneratedCodeViewModelAttribute}}
+ private bool {{setMethodName}}(ref {{Type}} field, {{Type}} value)
+ {
+ if ({{EqualityComparer_1}}<{{Type}}>.Default.Equals(field, value)) return false;
+
+ {{Type}} oldValue = field;
+
+ {{onChangingMethod}}(value);
+ {{onChangingMethod}}(oldValue, value);
+ {
+ field = value;
+ {{onPropertyChangedMethod}}();
+ }
+ {{onChangedMethod}}(value);
+ {{onChangedMethod}}(oldValue, value);
+
+ return true;
+ }
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangingMethod}}({{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangingMethod}}({{Type}} oldValue, {{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangedMethod}}({{Type}} newValue);
+
+ {{EditorBrowsableAttributeNever}}
+ {{GeneratedCodeViewModelAttribute}}
+ partial void {{onChangedMethod}}({{Type}} oldValue, {{Type}} newValue);
+ """);
+ }
+ else
+ {
+ declaration.AppendLine(
+ $"""
+ {GeneratedCodeViewModelAttribute}
+ private bool {setMethodName}(ref {Type} field, {Type} value) =>
+ throw new {NotImplementedException}("Generator Error: SetMethod is not used.");
+ """);
+ }
+
+ declaration.AppendLine("#endregion");
+ }
+ }
+
+ Declaration = declaration.ToString();
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/GeneratedBindableMembers.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/GeneratedBindableMembers.cs
new file mode 100644
index 0000000..d3c8624
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/GeneratedBindableMembers.cs
@@ -0,0 +1,239 @@
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Helpers;
+using Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+using SymbolExtensions = Aspid.MVVM.Generators.Helpers.SymbolExtensions;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public readonly struct GeneratedBindableMembers
+{
+ // TODO Aspid.MVVM.Generators – Write summary
+ public readonly string? Invoke;
+ public readonly string Declaration;
+ public readonly string PropertyName;
+ public readonly string PropertyType;
+ public readonly string? OnPropertyChangedName;
+
+ private GeneratedBindableMembers(
+ string? invoke,
+ string declaration,
+ string propertyName,
+ string propertyType,
+ string? onPropertyChangedName)
+ {
+ Invoke = invoke;
+ Declaration = declaration;
+ PropertyName = propertyName;
+ PropertyType = propertyType;
+ OnPropertyChangedName = onPropertyChangedName;
+ }
+
+ public static GeneratedBindableMembers CreateForRelayCommand(
+ string type,
+ string memberName)
+ {
+ const BindMode mode = BindMode.OneTime;
+
+ var fieldType = $"{OneTimeBindableMember}<{type}>";
+ var propertyType = $"{IReadOnlyValueBindableMember}<{type}>";
+ var propertyName = $"{memberName}Bindable";
+
+ var declaration = RecognizeDeclaration(mode, memberName, null, fieldType, propertyName, propertyType);
+
+ return new GeneratedBindableMembers(null, declaration, propertyName, propertyType, null);
+ }
+
+ public static GeneratedBindableMembers CreateForField(IFieldSymbol fieldSymbol)
+ {
+ var mode = fieldSymbol.GetBindMode();
+ var memberName = fieldSymbol.Name;
+
+ // __fieldName;
+ var fieldName = $"__{fieldSymbol.RemoveFieldPrefix()}Bindable";
+ var fieldType = RecognizeFieldType(fieldSymbol.Type, mode);
+
+ // _fieldName -> FieldNameBindable
+ var propertyName = $"{fieldSymbol.GetPropertyName()}Bindable";
+ var propertyType = RecognizePropertyType(fieldSymbol.Type, mode);
+
+ var invoke = RecognizeInvoke(mode, memberName, fieldName);
+ var declaration = RecognizeDeclaration(mode, memberName, fieldName, fieldType, propertyName, propertyType, $"Set{SymbolExtensions.GetPropertyName(memberName)}");
+
+ var onPropertyChangedName = mode is not BindMode.OneTime and not BindMode.OneWayToSource and not BindMode.None
+ ? $"On{fieldSymbol.GetPropertyName()}PropertyChanged"
+ : null;
+
+ return new GeneratedBindableMembers(invoke, declaration, propertyName, propertyType, onPropertyChangedName);
+ }
+
+ public static GeneratedBindableMembers CreateForProperty(IPropertySymbol propertySymbol)
+ {
+ var mode = propertySymbol.GetBindMode();
+ var memberName = propertySymbol.Name;
+
+ // PropertyName -> __propertyNameBindable
+ var fieldName = $"{propertySymbol.GetFieldName(prefix: "__")}Bindable";
+ var fieldType = RecognizeFieldType(propertySymbol.Type, mode);
+
+ // PropertyName -> PropertyNameBindable
+ var capitalizedName = propertySymbol.Name.CapitalizeFirstLetter();
+ var propertyName = $"{capitalizedName}Bindable";
+ var propertyType = RecognizePropertyType(propertySymbol.Type, mode);
+
+ var invoke = RecognizeInvoke(mode, memberName, fieldName);
+ var declaration = RecognizeDeclaration(mode, memberName, fieldName, fieldType, propertyName, propertyType);
+
+ var onPropertyChangedName = mode is not BindMode.OneTime and not BindMode.OneWayToSource and not BindMode.None
+ ? $"On{capitalizedName}PropertyChanged"
+ : null;
+
+ return new GeneratedBindableMembers(invoke, declaration, propertyName, propertyType, onPropertyChangedName);
+ }
+
+ public static GeneratedBindableMembers CreateForBindAlso(IPropertySymbol propertySymbol)
+ {
+ const BindMode mode = BindMode.OneWay;
+ var memberName = propertySymbol.Name;
+
+ // PropertyName -> __propertyNameBindable
+ var fieldName = $"{propertySymbol.GetFieldName(prefix: "__")}Bindable";
+ var fieldType = RecognizeFieldType(propertySymbol.Type, mode);
+
+ // PropertyName -> PropertyNameBindable
+ var capitalizedName = propertySymbol.Name.CapitalizeFirstLetter();
+ var propertyName = $"{capitalizedName}Bindable";
+ var propertyType = RecognizePropertyType(propertySymbol.Type, mode);
+
+ var invoke = RecognizeInvoke(mode, memberName, fieldName);
+ var declaration = RecognizeDeclaration(mode, memberName, fieldName, fieldType, propertyName, propertyType);
+
+ return new GeneratedBindableMembers(invoke, declaration, propertyName, propertyType, $"On{capitalizedName}PropertyChanged");
+ }
+
+ private static string RecognizeFieldType(ITypeSymbol type, BindMode mode)
+ {
+ var typeKind = type.TypeKind;
+
+ if (typeKind is TypeKind.TypeParameter)
+ {
+ if (type is ITypeParameterSymbol typeParameter)
+ {
+ typeKind = GetEffectiveTypeKind(typeParameter);
+ }
+ }
+
+ string result = mode switch
+ {
+ BindMode.OneWay => typeKind switch
+ {
+ TypeKind.Enum => OneWayEnumBindableMember,
+ TypeKind.Struct => OneWayStructBindableMember,
+ _ => OneWayBindableMember
+ },
+ BindMode.TwoWay => typeKind switch
+ {
+ TypeKind.Enum => TwoWayEnumBindableMember,
+ TypeKind.Struct => TwoWayStructBindableMember,
+ _ => TwoWayBindableMember
+ },
+ BindMode.OneTime => typeKind switch
+ {
+ TypeKind.Enum => OneTimeEnumBindableMember,
+ TypeKind.Struct => OneTimeStructBindableMember,
+ _ => OneTimeBindableMember
+ },
+ BindMode.OneWayToSource => typeKind switch
+ {
+ TypeKind.Enum => OneWayToSourceEnumBindableMember,
+ TypeKind.Struct => OneWayToSourceStructBindableMember,
+ _ => OneWayToSourceBindableMember
+ },
+ _ => string.Empty
+ };
+
+ return string.IsNullOrWhiteSpace(result)
+ ? string.Empty
+ : $"{result}<{type.ToDisplayStringGlobal()}>";
+
+ TypeKind GetEffectiveTypeKind(ITypeParameterSymbol typeParameter)
+ {
+ foreach (var constraint in typeParameter.ConstraintTypes)
+ {
+ if (constraint.TypeKind == TypeKind.Enum
+ || constraint.SpecialType == SpecialType.System_Enum)
+ {
+ return TypeKind.Enum;
+ }
+ }
+
+ return typeParameter.HasValueTypeConstraint ? TypeKind.Struct : TypeKind.Class;
+ }
+ }
+
+ private static string RecognizePropertyType(ITypeSymbol type, BindMode mode)
+ {
+ string result = mode switch
+ {
+ BindMode.TwoWay => IBindableMember,
+ BindMode.OneWay => IReadOnlyBindableMember,
+ BindMode.OneTime or BindMode.OneWayToSource => IReadOnlyValueBindableMember,
+ _ => string.Empty
+ };
+
+ return string.IsNullOrWhiteSpace(result)
+ ? string.Empty
+ : $"{result}<{type.ToDisplayStringGlobal()}>";
+ }
+
+ private static string? RecognizeInvoke(BindMode mode, string memberName, string fieldName)
+ {
+ return mode is not (BindMode.OneWayToSource or BindMode.OneTime)
+ ? $"{fieldName}?.Invoke({memberName});"
+ : null;
+ }
+
+ private static string RecognizeDeclaration(
+ BindMode mode,
+ string memberName,
+ string? fieldName,
+ string fieldType,
+ string propertyName,
+ string propertyType,
+ string? setMethod = null)
+ {
+ if (mode is BindMode.OneTime)
+ {
+ return
+ $"""
+ {GeneratedCodeViewModelAttribute}
+ public {propertyType} {propertyName} =>
+ {fieldType}.Get({memberName});
+ """;
+ }
+
+ setMethod ??= $"value => {memberName} = value";
+
+ // For properties, we use a property setter directly instead of a method reference
+ var instantiate = mode switch
+ {
+ BindMode.OneWay => $"{fieldName} ??= new({memberName})",
+ BindMode.TwoWay => $"{fieldName} ??= new({memberName}, {setMethod})",
+ BindMode.OneWayToSource => $"{fieldName} ??= new({setMethod})",
+ _ => string.Empty
+ };
+
+ return
+ $"""
+ {EditorBrowsableAttributeNever}
+ {GeneratedCodeViewModelAttribute}
+ private {fieldType} {fieldName};
+
+ {GeneratedCodeViewModelAttribute}
+ public {propertyType} {propertyName} =>
+ {instantiate};
+ """;
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/IBindableMemberInfo.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/IBindableMemberInfo.cs
new file mode 100644
index 0000000..20ec3ef
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Infos/IBindableMemberInfo.cs
@@ -0,0 +1,19 @@
+using Microsoft.CodeAnalysis;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+
+public interface IBindableMemberInfo
+{
+ public ISymbol Member { get; }
+
+ public string Type { get; }
+
+ public string Name { get; }
+
+ public IdData Id { get; }
+
+ public BindMode Mode { get; }
+
+ public GeneratedBindableMembers Bindable { get; }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Inheritor.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Inheritor.cs
index 9ea8296..122bb98 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Inheritor.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Inheritor.cs
@@ -1,4 +1,4 @@
-namespace Aspid.MVVM.Generators.ViewModels.Data;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data;
public enum Inheritor
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableBindAlso.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableBindAlso.cs
deleted file mode 100644
index 966ce75..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableBindAlso.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members;
-
-public sealed class BindableBindAlso : BindableMember, IEquatable
-{
- public BindableBindAlso(ISymbol member)
- : base(member, BindMode.OneWay, member.GetSymbolType()?.ToDisplayStringGlobal() ?? string.Empty, member.Name, member.Name, string.Empty, member.GetSymbolType()?.TypeKind ?? TypeKind.Class) { }
-
- public override bool Equals(object? obj) =>
- obj is BindableBindAlso other && Equals(other);
-
- public bool Equals(BindableBindAlso other) =>
- SymbolEqualityComparer.Default.Equals(Member, other.Member);
-
- public override int GetHashCode() =>
- SymbolEqualityComparer.Default.GetHashCode(Member);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableCommand.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableCommand.cs
deleted file mode 100644
index 89e99fc..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableCommand.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System.Linq;
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using static Aspid.MVVM.Generators.Descriptions.General;
-
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members;
-
-public sealed class BindableCommand : BindableMember
-{
- public readonly string CanExecute;
-
- public BindableCommand(IMethodSymbol command, string? canExecute, bool isLambda, bool isMethod)
- : base(command, BindMode.OneTime, GetTypeName(command), $"{command.GetFieldName("__")}Command", $"{command.GetPropertyName()}Command", "Command")
- {
- CanExecute = GetCanExecuteAction(command, isLambda, isMethod, canExecute);
- }
-
- public string ToDeclarationCommandString()
- {
- return
- $"""
- {GeneratedCodeViewModelAttribute}
- [{EditorBrowsableAttribute}({EditorBrowsableState}.Never)]
- private {Type} {SourceName};
-
- {GeneratedCodeViewModelAttribute}
- private {Type} {GeneratedName} => {SourceName} ??= new {Type}({Member.Name}{CanExecute});
- """;
- }
-
- private static string GetTypeName(IMethodSymbol command)
- {
- var type = new StringBuilder(RelayCommand);
- var parameters = command.Parameters;
- if (parameters.Length <= 0) return type.ToString();
-
- type.Append("<");
-
- foreach (var parameter in parameters)
- type.Append($"{parameter.Type.ToDisplayStringGlobal()},");
-
- type.Length--;
- type.Append(">");
-
- return type.ToString();
- }
-
- private static string GetCanExecuteAction(IMethodSymbol command, bool isLambda, bool isMethod, string? canExecute)
- {
- var canExecuteName = new StringBuilder(canExecute ?? "");
-
- if (canExecuteName.Length != 0)
- {
- if (!isLambda)
- {
- canExecuteName.Insert(0, ", ");
- }
- else
- {
- var parameters = command.Parameters;
- var missingParameters = string.Join(", ", Enumerable.Repeat("_", parameters.Length));
-
- canExecuteName.Insert(0, $", ({missingParameters}) => ");
- if (isLambda && isMethod) canExecuteName.Append("()");
- }
- }
-
- return canExecuteName.ToString();
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableField.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableField.cs
deleted file mode 100644
index d751fc6..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableField.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis.CSharp;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using static Aspid.MVVM.Generators.Descriptions.General;
-
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members;
-
-public class BindableField : BindableMember
-{
- public readonly bool IsReadOnly;
- public readonly string GetAccessAsText;
- public readonly string SetAccessAsText;
- public readonly string GeneralAccessAsText;
- public readonly ImmutableArray BindAlso;
-
- public BindableField(IFieldSymbol field, BindMode mode, ImmutableArray bindAlso)
- : base(field,
- mode,
- field.Type.ToDisplayStringGlobal(),
- field.Name,
- field.IsConst ? field.Name : field.GetPropertyName(),
- string.Empty,
- field.Type.TypeKind)
- {
- BindAlso = bindAlso;
- IsReadOnly = mode is BindMode.OneTime;
-
- var accessors = GetAccessors(field);
-
- GetAccessAsText = accessors.Get == accessors.General
- ? string.Empty
- : ConvertAccessToText(accessors.Get);
-
- SetAccessAsText = accessors.Set == accessors.General
- ? string.Empty
- : ConvertAccessToText(accessors.Set);
-
- GeneralAccessAsText = ConvertAccessToText(accessors.General);
- }
-
- public string ToDeclarationPropertyString()
- {
- return IsReadOnly
- ? $"""
- {GeneratedCodeViewModelAttribute}
- {GeneralAccessAsText}{Type} {GeneratedName} => {SourceName};
- """
- : $$"""
- {{GeneratedCodeViewModelAttribute}}
- {{GeneralAccessAsText}}{{Type}} {{GeneratedName}}
- {
- {{GetAccessAsText}}get => {{SourceName}};
- {{SetAccessAsText}}set => Set{{GeneratedName}}(value);
- }
- """;
- }
-
- // TODO Nullable?
- public string ToSetMethodString()
- {
- if (Mode is BindMode.OneTime) return string.Empty;
-
- var setMethod = $"Set{GeneratedName}";
- var onMethodChanged = $"On{GeneratedName}Changed";
- var onMethodChanging = $"On{GeneratedName}Changing";
-
- var eventInvoke = ToInvokeBindableMemberString();
- var keyWordThis = !Member.IsStatic ? "this." : string.Empty;
-
- foreach (var property in BindAlso)
- eventInvoke += $"\n\t{property.ToInvokeBindableMemberString()}";
-
- return
- $$"""
- {{GeneratedCodeViewModelAttribute}}
- private void {{setMethod}}({{Type}} value)
- {
- if ({{EqualityComparer}}<{{Type}}>.Default.Equals({{SourceName}}, value)) return;
-
- {{onMethodChanging}}({{SourceName}}, value);
- {{keyWordThis}}{{SourceName}} = value;
- {{eventInvoke}}
- {{onMethodChanged}}(value);
- }
-
- {{GeneratedCodeViewModelAttribute}}
- partial void {{onMethodChanging}}({{Type}} oldValue, {{Type}} newValue);
-
- {{GeneratedCodeViewModelAttribute}}
- partial void {{onMethodChanged}}({{Type}} newValue);
- """;
- }
-
- private static string ConvertAccessToText(SyntaxKind syntaxKind) => syntaxKind switch
- {
- SyntaxKind.PrivateKeyword => "private ",
- SyntaxKind.ProtectedKeyword => "protected ",
- SyntaxKind.PublicKeyword => "public ",
- _ => ""
- };
-
- private static Accessors GetAccessors(IFieldSymbol field)
- {
- var accessors = new Accessors(SyntaxKind.PrivateKeyword, SyntaxKind.PrivateKeyword);
- if (!field.HasAnyAttribute(out var accessAttribute, AccessAttribute)) return accessors;
-
- if (accessAttribute!.ConstructorArguments.Length == 1)
- {
- var value = (SyntaxKind)(int)(accessAttribute.ConstructorArguments[0].Value ?? SyntaxKind.PrivateKeyword);
- accessors.Get = value;
- accessors.Set = value;
- }
-
- foreach (var argument in accessAttribute!.NamedArguments)
- {
- switch (argument.Key)
- {
- case "Get": accessors.Get = (SyntaxKind)(int)(argument.Value.Value ?? SyntaxKind.PrivateKeyword); break;
- case "Set": accessors.Set = (SyntaxKind)(int)(argument.Value.Value ?? SyntaxKind.PrivateKeyword); break;
- }
- }
-
- return accessors;
- }
-
- private ref struct Accessors(SyntaxKind get, SyntaxKind set)
- {
- public SyntaxKind Get = get;
- public SyntaxKind Set = set;
-
- public SyntaxKind General => GetGeneralAccessor(Get, Set);
-
- private static SyntaxKind GetGeneralAccessor(SyntaxKind getAccessor, SyntaxKind setAccessor)
- {
- if (setAccessor == getAccessor) return getAccessor;
- if (getAccessor == SyntaxKind.PublicKeyword) return getAccessor;
- if (setAccessor == SyntaxKind.PublicKeyword) return setAccessor;
- if (getAccessor == SyntaxKind.ProtectedKeyword) return getAccessor;
- if (setAccessor == SyntaxKind.ProtectedKeyword) return setAccessor;
-
- return SyntaxKind.PrivateKeyword;
- }
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableMember.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableMember.cs
deleted file mode 100644
index d680117..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/BindableMember.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Aspid.MVVM.Generators.Ids.Data;
-using static Aspid.Generator.Helpers.SymbolExtensions;
-using static Aspid.MVVM.Generators.Descriptions.General;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members;
-
-public abstract class BindableMember : BindableMember
- where T : ISymbol
-{
- public readonly T Member;
-
- protected BindableMember(T member, BindMode mode, string type, string sourceName, string generatedName, string idPostfix, TypeKind typeKind = TypeKind.Class)
- : base(member, mode, type, sourceName, generatedName, idPostfix, typeKind)
- {
- Member = member;
- }
-}
-
-public abstract class BindableMember
-{
- public readonly string Type;
- public readonly string SourceName;
- public readonly string GeneratedName;
- public readonly string BindableMemberPropertyType;
-
- public readonly IdData Id;
- public readonly BindMode Mode;
-
- private readonly string? _bindableType;
- private readonly string _bindableFieldName;
-
- protected BindableMember(ISymbol member, BindMode mode, string type, string name, string idPostfix, TypeKind typeKind = TypeKind.Class)
- : this(member, mode, type, name, name, idPostfix, typeKind) { }
-
- protected BindableMember(
- ISymbol member,
- BindMode mode,
- string type,
- string sourceName,
- string generatedName,
- string idPostfix,
- TypeKind typeKind = TypeKind.Class)
- {
- Type = type;
- Mode = mode;
- SourceName = sourceName;
- GeneratedName = generatedName;
- Id = new IdData(member, idPostfix);
-
- switch (mode)
- {
- case BindMode.OneWay:
- _bindableType = typeKind switch
- {
- TypeKind.Enum => OneWayEnumBindableMember,
- TypeKind.Struct => OneWayStructBindableMember,
- _ => OneWayBindableMember
- };
- break;
-
- case BindMode.TwoWay:
- _bindableType = typeKind switch
- {
- TypeKind.Enum => TwoWayEnumBindableMember,
- TypeKind.Struct => TwoWayStructBindableMember,
- _ => TwoWayBindableMember
- };
- break;
-
- case BindMode.OneTime:
- _bindableType = typeKind switch
- {
- TypeKind.Enum => OneTimeEnumBindableMember,
- TypeKind.Struct => OneTimeStructBindableMember,
- _ => OneTimeBindableMember
- };
- break;
-
- case BindMode.OneWayToSource:
- _bindableType = typeKind switch
- {
- TypeKind.Enum => OneWayToSourceEnumBindableMember,
- TypeKind.Struct => OneWayToSourceStructBindableMember,
- _ => OneWayToSourceBindableMember
- };
- break;
- }
-
- BindableMemberPropertyType = Mode is BindMode.OneTime
- ? IReadOnlyValueBindableMember
- : IReadOnlyBindableMember;
-
- _bindableFieldName = $"__{RemoveFieldPrefix(GetFieldName(generatedName, null))}Bindable";
- }
-
- public string? ToBindableMemberFieldDeclarationString()
- {
- if (Mode is BindMode.OneTime) return null;
-
- return _bindableType is null
- ? null
- : $"""
- [{EditorBrowsableAttribute}({EditorBrowsableState}.Never)]
- {GeneratedCodeViewModelAttribute}
- private {_bindableType}<{Type}> {_bindableFieldName};
- """;
- }
-
- public string ToBindableMemberPropertyDeclarationString()
- {
- var instantiate = Mode switch
- {
- BindMode.OneWay => $"{_bindableFieldName} ??= new({GeneratedName})",
- BindMode.TwoWay => $"{_bindableFieldName} ??= new({GeneratedName}, Set{GeneratedName})",
- BindMode.OneTime => $"{_bindableType}<{Type}>.Get({GeneratedName})",
- BindMode.OneWayToSource => $"{_bindableFieldName} ??= new(Set{GeneratedName})",
- _ => string.Empty
- };
-
- return $"""
- {GeneratedCodeViewModelAttribute}
- public {BindableMemberPropertyType}<{Type}> {GeneratedName}Bindable =>
- {instantiate};
- """;
- }
-
- // TODO Nullable?
- public string ToInvokeBindableMemberString() => Mode is not (BindMode.OneWayToSource or BindMode.OneTime)
- ? $"this.{_bindableFieldName}?.Invoke({SourceName});"
- : string.Empty;
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/Collections/IdLengthMemberGroup.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/Collections/IdLengthMemberGroup.cs
index d686f96..047566e 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/Collections/IdLengthMemberGroup.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/Collections/IdLengthMemberGroup.cs
@@ -1,15 +1,16 @@
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members.Collections;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Members.Collections;
-public readonly struct IdLengthMemberGroup(int length, ImmutableArray members)
+public readonly struct IdLengthMemberGroup(int length, ImmutableArray members)
{
public readonly int Length = length;
- public readonly ImmutableArray Members = members;
+ public readonly ImmutableArray Members = members;
- public static ImmutableArray Create(ImmutableArray bindableMembers)
+ public static ImmutableArray Create(ImmutableArray bindableMembers)
{
var bindableMembersCountByLength = new Dictionary();
@@ -22,7 +23,7 @@ public static ImmutableArray Create(ImmutableArray>();
+ var idGroups = new Dictionary>();
foreach (var bindableMember in bindableMembers)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/CustomViewModelInterface.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/CustomViewModelInterface.cs
index 5edb3ef..8c2ac44 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/CustomViewModelInterface.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/Members/CustomViewModelInterface.cs
@@ -1,6 +1,6 @@
using Microsoft.CodeAnalysis;
-namespace Aspid.MVVM.Generators.ViewModels.Data.Members;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data.Members;
public readonly struct CustomViewModelInterface(string id, IPropertySymbol property, ITypeSymbol @interface)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/PropertyNotificationData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/PropertyNotificationData.cs
new file mode 100644
index 0000000..d0c6ac8
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/PropertyNotificationData.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data;
+
+public sealed class PropertyNotificationData
+{
+ // Key - propertyName, Value - List of line numbers
+ public Dictionary> OnPropertyChangedCalls { get; } = [];
+
+ // Key - type, Value - Dictionary (propertyName -> List of line numbers)
+ public Dictionary>> SetFieldCallsByType { get; } = [];
+
+ public HashSet PropertiesRequiringSetFieldBody { get; } = [];
+
+ public bool HasOnPropertyChangedCalls => OnPropertyChangedCalls.Count > 0;
+
+ public bool HasSetFieldCalls => SetFieldCallsByType.Count > 0;
+
+ public void AddOnPropertyChangedCall(string propertyName, int line)
+ {
+ if (!OnPropertyChangedCalls.TryGetValue(propertyName, out var lines))
+ {
+ lines = [];
+ OnPropertyChangedCalls[propertyName] = lines;
+ }
+
+ lines.Add(line);
+ }
+
+ public void AddSetFieldCall(string propertyName, int line, string type)
+ {
+ if (!SetFieldCallsByType.TryGetValue(type, out var propertyCalls))
+ {
+ propertyCalls = [];
+ SetFieldCallsByType[type] = propertyCalls;
+ }
+
+ if (!propertyCalls.TryGetValue(propertyName, out var lines))
+ {
+ lines = [];
+ propertyCalls[propertyName] = lines;
+ }
+
+ lines.Add(line);
+ PropertiesRequiringSetFieldBody.Add(propertyName);
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/ViewModelData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/ViewModelData.cs
index d09ff45..32385ae 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/ViewModelData.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Data/ViewModelData.cs
@@ -2,18 +2,20 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using Aspid.MVVM.Generators.ViewModels.Data.Members.Collections;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Members;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Members.Collections;
-namespace Aspid.MVVM.Generators.ViewModels.Data;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Data;
public readonly struct ViewModelData(
Inheritor inheritor,
INamedTypeSymbol symbol,
ClassDeclarationSyntax declaration,
- ImmutableArray members,
+ ImmutableArray members,
ImmutableArray idGroups,
- Dictionary customViewModelInterfaces)
+ Dictionary customViewModelInterfaces,
+ PropertyNotificationData propertyNotificationData)
{
public readonly string Name = symbol.Name;
@@ -21,7 +23,9 @@ public readonly struct ViewModelData(
public readonly INamedTypeSymbol Symbol = symbol;
public readonly ClassDeclarationSyntax Declaration = declaration;
- public readonly ImmutableArray Members = members;
+ public readonly ImmutableArray Members = members;
public readonly ImmutableArray IdGroups = idGroups;
+
public readonly Dictionary CustomViewModelInterfaces = customViewModelInterfaces;
+ public readonly PropertyNotificationData PropertyNotificationData = propertyNotificationData;
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/InvocationExpressionSyntaxExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/InvocationExpressionSyntaxExtensions.cs
new file mode 100644
index 0000000..5fdb9e6
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/InvocationExpressionSyntaxExtensions.cs
@@ -0,0 +1,13 @@
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+
+public static class InvocationExpressionSyntaxExtensions
+{
+ public static string? GetMethodName(this InvocationExpressionSyntax invocation) => invocation.Expression switch
+ {
+ IdentifierNameSyntax identifier => identifier.Identifier.Text,
+ MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text,
+ _ => null
+ };
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/MethodUsageAnalyzer.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/MethodUsageAnalyzer.cs
new file mode 100644
index 0000000..7e01898
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/MethodUsageAnalyzer.cs
@@ -0,0 +1,23 @@
+using System.Linq;
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+
+public static class MethodUsageAnalyzer
+{
+ public static HashSet GetUsedMethods(TypeDeclarationSyntax declaration, HashSet methodNames)
+ {
+ var usedMethods = new HashSet();
+
+ foreach (var invocation in declaration.DescendantNodes().OfType())
+ {
+ var invokedMethodName = invocation.GetMethodName();
+
+ if (invokedMethodName is not null && methodNames.Contains(invokedMethodName))
+ usedMethods.Add(invokedMethodName);
+ }
+
+ return usedMethods;
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/PropertyNotificationAnalyzer.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/PropertyNotificationAnalyzer.cs
new file mode 100644
index 0000000..78df8b1
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/PropertyNotificationAnalyzer.cs
@@ -0,0 +1,136 @@
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+
+public static class PropertyNotificationAnalyzer
+{
+ ///
+ /// Анализирует класс и возвращает данные о вызовах OnPropertyChanged и SetField.
+ ///
+ public static Data.PropertyNotificationData Analyze(
+ TypeDeclarationSyntax classDeclaration,
+ IReadOnlyDictionary bindableProperties) // propertyName -> type
+ {
+ var data = new Data.PropertyNotificationData();
+
+ foreach (var invocation in classDeclaration.DescendantNodes().OfType())
+ {
+ var methodName = invocation.GetMethodName();
+
+ switch (methodName)
+ {
+ case "OnPropertyChanged":
+ AnalyzeOnPropertyChanged(invocation, bindableProperties, data);
+ break;
+
+ case "SetField":
+ AnalyzeSetField(invocation, bindableProperties, data);
+ break;
+ }
+ }
+
+ return data;
+ }
+
+ private static void AnalyzeOnPropertyChanged(
+ InvocationExpressionSyntax invocation,
+ IReadOnlyDictionary bindableProperties,
+ Data.PropertyNotificationData data)
+ {
+ var line = invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1;
+ var arguments = invocation.ArgumentList.Arguments;
+
+ if (arguments.Count == 0)
+ {
+ // OnPropertyChanged() - определяем свойство по контексту (ищем свойство в котором вызов)
+ var propertyName = FindContainingPropertyName(invocation);
+ if (propertyName is not null && bindableProperties.ContainsKey(propertyName))
+ {
+ data.AddOnPropertyChangedCall(propertyName, line);
+ }
+ }
+ else
+ {
+ // OnPropertyChanged(nameof(FirstName)) или OnPropertyChanged("FirstName")
+ var propertyName = ExtractPropertyName(arguments[0].Expression);
+ if (propertyName is not null && bindableProperties.ContainsKey(propertyName))
+ {
+ data.AddOnPropertyChangedCall(propertyName, line);
+ }
+ }
+ }
+
+ private static void AnalyzeSetField(
+ InvocationExpressionSyntax invocation,
+ IReadOnlyDictionary bindableProperties,
+ Data.PropertyNotificationData data)
+ {
+ var line = invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1;
+ var arguments = invocation.ArgumentList.Arguments;
+
+ // SetField(ref _field, value) - минимум 2 аргумента
+ // SetField(ref _field, value, nameof(Property)) - 3 аргумента
+ if (arguments.Count < 2) return;
+
+ string? propertyName;
+
+ if (arguments.Count >= 3)
+ {
+ // Третий аргумент - имя свойства
+ propertyName = ExtractPropertyName(arguments[2].Expression);
+ }
+ else
+ {
+ // Определяем по контексту свойства (вызов внутри свойства)
+ propertyName = FindContainingPropertyName(invocation);
+ }
+
+ if (propertyName is not null && bindableProperties.TryGetValue(propertyName, out var type))
+ {
+ data.AddSetFieldCall(propertyName, line, type);
+ }
+ }
+
+ private static string? FindContainingPropertyName(SyntaxNode node)
+ {
+ var current = node.Parent;
+ while (current is not null)
+ {
+ if (current is PropertyDeclarationSyntax property)
+ {
+ return property.Identifier.Text;
+ }
+ current = current.Parent;
+ }
+ return null;
+ }
+
+ private static string? ExtractPropertyName(ExpressionSyntax expression)
+ {
+ return expression switch
+ {
+ // nameof(FirstName)
+ InvocationExpressionSyntax { Expression: IdentifierNameSyntax { Identifier.Text: "nameof" } } nameofExpr
+ when nameofExpr.ArgumentList.Arguments.Count > 0
+ => GetIdentifierFromExpression(nameofExpr.ArgumentList.Arguments[0].Expression),
+
+ // "FirstName"
+ LiteralExpressionSyntax literal => literal.Token.ValueText,
+
+ _ => null
+ };
+ }
+
+ private static string? GetIdentifierFromExpression(ExpressionSyntax expression)
+ {
+ return expression switch
+ {
+ IdentifierNameSyntax identifier => identifier.Identifier.Text,
+ MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text,
+ _ => null
+ };
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/SymbolExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/SymbolExtensions.cs
index 8ed9654..18ea793 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/SymbolExtensions.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Extensions/SymbolExtensions.cs
@@ -1,30 +1,39 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.ViewModels.Data;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.ViewModels.Extensions;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
public static class SymbolExtensions
{
public static BindMode GetBindMode(this ISymbol member)
{
- if (member.HasAnyAttribute(out var attribute, Classes.BindAttribute, Classes.OneWayBindAttribute,
+ if (member.TryGetAnyAttributeInSelf(out var attribute, Classes.BindAttribute, Classes.OneWayBindAttribute,
Classes.TwoWayBindAttribute, Classes.OneTimeBindAttribute, Classes.OneWayToSourceBindAttribute))
{
- var attributeName = attribute!.AttributeClass!.ToDisplayString();
+ var attributeName = attribute!.AttributeClass.ToDisplayString();
if (attributeName == Classes.BindAttribute.FullName)
{
- if (attribute!.ConstructorArguments.Length is 0)
+ if (attribute.ConstructorArguments.Length is 0)
{
- if (member is not IFieldSymbol field) return BindMode.TwoWay;
- if (field.IsReadOnly || field.IsConst) return BindMode.OneTime;
-
+ if (member is IFieldSymbol field)
+ {
+ if (field.IsReadOnly || field.IsConst) return BindMode.OneTime;
+ return BindMode.TwoWay;
+ }
+
+ if (member is IPropertySymbol property)
+ {
+ if (property.IsReadOnly) return Determine(BindMode.OneWay);
+ if (property.IsWriteOnly) return Determine(BindMode.OneWayToSource);
+ }
+
return BindMode.TwoWay;
}
- return Determine((BindMode)(int)attribute!.ConstructorArguments[0].Value!);
+ return Determine((BindMode)(int)attribute.ConstructorArguments[0].Value!);
}
if (attributeName == Classes.OneWayBindAttribute.FullName)
@@ -51,6 +60,13 @@ BindMode Determine(BindMode current)
if (field.IsReadOnly && current is not BindMode.OneTime) return BindMode.None;
break;
}
+
+ case IPropertySymbol property:
+ {
+ if (property.IsReadOnly && current is not (BindMode.OneTime or BindMode.OneWay)) return BindMode.None;
+ if (property.IsWriteOnly && current is not BindMode.OneWayToSource) return BindMode.None;
+ break;
+ }
}
return current;
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableBindAlsoFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableBindAlsoFactory.cs
index 19ae3c9..7518abe 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableBindAlsoFactory.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableBindAlsoFactory.cs
@@ -1,23 +1,23 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.ViewModels.Factories;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Factories;
public static class BindableBindAlsoFactory
{
- public static IReadOnlyCollection Create(ImmutableArray members)
+ public static IReadOnlyCollection Create(ImmutableArray members)
{
var set = new HashSet();
- var bindableBindAlso = new List();
+ var bindableBindAlso = new List();
foreach (var member in members)
{
- if (!member.HasAnyAttribute(BindAttribute, OneWayBindAttribute, TwoWayBindAttribute)) continue;
- if (!member.HasAnyAttribute(out var attribute, BindAlsoAttribute)) continue;
+ if (!member.HasAnyAttributeInSelf(BindAttribute, OneWayBindAttribute, TwoWayBindAttribute)) continue;
+ if (!member.TryGetAnyAttributeInSelf(out var attribute, BindAlsoAttribute)) continue;
var value = attribute!.ConstructorArguments[0].Value;
if (value is null) continue;
@@ -27,8 +27,10 @@ public static IReadOnlyCollection Create(ImmutableArray Create(
+ public static IReadOnlyCollection Create(
ImmutableArray methods,
ImmutableArray properties,
ImmutableArray generatedBoolProperties)
{
- var bindableCommands = new List();
+ var bindableCommands = new List();
var boolMethods = methods.Where(boolMethods =>
boolMethods.ReturnType.ToString() is CanExecuteReturnType).ToImmutableArray();
@@ -27,7 +27,7 @@ public static IReadOnlyCollection Create(
foreach (var method in methods)
{
- if (!method.HasAnyAttribute(out var attribute, Classes.RelayCommandAttribute)) continue;
+ if (!method.TryGetAnyAttributeInSelf(out var attribute, Classes.RelayCommandAttribute)) continue;
var canExecuteArgument = attribute!.NamedArguments
.Where(pair => pair.Key == "CanExecute")
@@ -37,8 +37,8 @@ public static IReadOnlyCollection Create(
var canExecute = GetCanExecute(canExecuteArgument, method, boolMethods, boolProperties, generatedBoolProperties);
bindableCommands.Add(canExecute.isEixst ?
- new BindableCommand(method, canExecuteArgument, canExecute.isLamda, canExecute.isMethod) :
- new BindableCommand(method, null, false, false));
+ new BindableCommandInfo(method, canExecuteArgument, canExecute.isLamda, canExecute.isMethod) :
+ new BindableCommandInfo(method, null, false, false));
}
return bindableCommands;
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableFieldFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableFieldFactory.cs
index df4b51a..ae6cdb3 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableFieldFactory.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableFieldFactory.cs
@@ -1,20 +1,17 @@
-using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
using System.Collections.Generic;
using System.Collections.Immutable;
-using Aspid.MVVM.Generators.ViewModels.Extensions;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using BindMode = Aspid.MVVM.Generators.ViewModels.Data.BindMode;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+using BindMode = Aspid.MVVM.Generators.Generators.ViewModels.Data.BindMode;
-namespace Aspid.MVVM.Generators.ViewModels.Factories;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Factories;
public static class BindableFieldFactory
{
- public static IReadOnlyCollection Create(ImmutableArray fields, IReadOnlyCollection bindableBindAlsos)
+ public static IReadOnlyCollection Create(ImmutableArray fields)
{
- var bindableFields = new List();
+ var bindableFields = new List();
foreach (var field in fields)
{
@@ -28,36 +25,18 @@ public static IReadOnlyCollection Create(ImmutableArray GetBindableBindAlso(IFieldSymbol field, IReadOnlyCollection allBindableBindAlsos)
- {
- var set = new HashSet();
-
- foreach (var attribute in field.GetAttributes())
- {
- if (attribute.AttributeClass != null &&
- attribute.AttributeClass.ToDisplayStringGlobal() == BindAlsoAttribute.Global)
- {
- var value = attribute.ConstructorArguments[0].Value;
- if (value is null) continue;
-
- set.Add(value.ToString());
- }
- }
-
- return allBindableBindAlsos.Where(bindableBindAlso =>
- set.Contains(bindableBindAlso.SourceName) || set.Contains(bindableBindAlso.GeneratedName)).ToImmutableArray();
- }
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableMembersFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableMembersFactory.cs
index 4c94839..8eb7fb0 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableMembersFactory.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindableMembersFactory.cs
@@ -1,33 +1,68 @@
using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
+using Aspid.MVVM.Generators.Helpers;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
-namespace Aspid.MVVM.Generators.ViewModels.Factories;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Factories;
public static class BindableMembersFactory
{
- public static ImmutableArray Create(ITypeSymbol symbol)
+ public static ImmutableArray Create(
+ ITypeSymbol symbol,
+ TypeDeclarationSyntax declaration,
+ out PropertyNotificationData propertyNotificationData)
{
var members = new MembersByGroup(symbol);
+ propertyNotificationData = CreatePropertyNotificationData(symbol, declaration);
+ var bindableFields = BindableFieldFactory.Create(members.Fields);
var bindableBindAlso = BindableBindAlsoFactory.Create(members.All);
- var bindableFields = BindableFieldFactory.Create(members.Fields, bindableBindAlso);
+ var bindableProperties = BindablePropertyFactory.Create(declaration, members.Properties, propertyNotificationData);
var generatedProperties = bindableFields
.Where(field => field.Type.ToString() == "bool")
- .Select(field => field.GeneratedName)
+ .Select(field => field.Name)
+ .Concat(bindableProperties
+ .Where(property => property.Type.ToString() == "bool")
+ .Select(property => property.Name))
.ToImmutableArray();
var bindableCommands = BindableCommandFactory.Create(members.Methods, members.Properties, generatedProperties);
- var bindableMembers = new List(bindableBindAlso.Count + bindableFields.Count + bindableCommands.Count);
+
+ var filteredBindableBindAlso = bindableBindAlso.Where(b => !b.HasBindAttribute).ToList();
+ var bindableMembers = new List(filteredBindableBindAlso.Count + bindableFields.Count + bindableProperties.Count + bindableCommands.Count);
bindableMembers.AddRange(bindableFields);
+ bindableMembers.AddRange(bindableProperties);
bindableMembers.AddRange(bindableCommands);
- bindableMembers.AddRange(bindableBindAlso);
+ bindableMembers.AddRange(filteredBindableBindAlso);
return bindableMembers.ToImmutableArray();
}
+
+ private static PropertyNotificationData CreatePropertyNotificationData(ITypeSymbol symbol, TypeDeclarationSyntax candidate)
+ {
+ var members = new MembersByGroup(symbol);
+
+ var bindablePropertiesDict = members.Properties
+ .Where(property => property.GetBindMode() is not BindMode.None)
+ .ToDictionary(property => property.Name, property => property.Type.ToDisplayStringGlobal());
+
+ var bindableFieldsDict = members.Fields
+ .Where(field => field.GetBindMode() is not BindMode.None)
+ .ToDictionary(field => field.GetPropertyName(), field => field.Type.ToDisplayStringGlobal());
+
+ foreach (var pair in bindableFieldsDict)
+ {
+ bindablePropertiesDict[pair.Key] = pair.Value;
+ }
+
+ return PropertyNotificationAnalyzer.Analyze(candidate, bindablePropertiesDict);
+ }
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindablePropertyFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindablePropertyFactory.cs
new file mode 100644
index 0000000..03b70e6
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/BindablePropertyFactory.cs
@@ -0,0 +1,64 @@
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Aspid.MVVM.Generators.Helpers;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Aspid.MVVM.Generators.Generators.ViewModels.Extensions;
+using BindMode = Aspid.MVVM.Generators.Generators.ViewModels.Data.BindMode;
+
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Factories;
+
+public static class BindablePropertyFactory
+{
+ public static IReadOnlyCollection Create(
+ TypeDeclarationSyntax declaration,
+ ImmutableArray properties,
+ PropertyNotificationData propertyNotificationData)
+ {
+ var bindableProperties = new List();
+
+ var setMethodNames = new HashSet(properties
+ .Select(p => $"Set{p.Name.CapitalizeFirstLetter()}Field"));
+
+ var usedSetMethods = MethodUsageAnalyzer.GetUsedMethods(declaration, setMethodNames);
+
+ foreach (var property in properties)
+ {
+ var mode = property.GetBindMode();
+
+ switch (mode)
+ {
+ case BindMode.OneTime:
+ case BindMode.OneWay:
+ {
+ if (property.IsWriteOnly) continue;
+ break;
+ }
+ case BindMode.TwoWay:
+ {
+ if (property.IsReadOnly || property.IsWriteOnly) continue;
+ break;
+ }
+ case BindMode.OneWayToSource:
+ {
+ if (property.IsReadOnly) continue;
+ break;
+ }
+
+ case BindMode.None:
+ default: continue;
+ }
+
+ var setMethodName = $"Set{property.Name.CapitalizeFirstLetter()}Field";
+ var isSetMethodUsed = usedSetMethods.Contains(setMethodName)
+ || propertyNotificationData.PropertiesRequiringSetFieldBody.Contains(property.Name);
+
+ bindableProperties.Add(new BindablePropertyInfo(property, mode, isSetMethodUsed));
+ }
+
+ return bindableProperties;
+ }
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/CustomViewModelInterfacesFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/CustomViewModelInterfacesFactory.cs
index 8218543..b21e919 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/CustomViewModelInterfacesFactory.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/Factories/CustomViewModelInterfacesFactory.cs
@@ -1,12 +1,12 @@
using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
-using Aspid.MVVM.Generators.Ids.Extensions;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
+using Aspid.MVVM.Generators.Generators.Ids.Extensions;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Members;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.ViewModels.Factories;
+namespace Aspid.MVVM.Generators.Generators.ViewModels.Factories;
public static class CustomViewModelInterfacesFactory
{
@@ -22,7 +22,7 @@ public static Dictionary Create(ITypeSymbol sy
void AddMembers(ITypeSymbol @interface)
{
- if (!@interface.HasInterfaceInSelfOrBases(IViewModel)) return;
+ if (!@interface.HasAnyInterfaceInSelfAndBases(IViewModel)) return;
foreach (var property in @interface.GetMembers()
.OfType()
@@ -34,7 +34,7 @@ void AddMembers(ITypeSymbol @interface)
|| type.Contains(IReadOnlyValueBindableMember);
}))
{
- if (property.HasAnyAttribute(IgnoreAttribute)) continue;
+ if (property.HasAnyAttributeInSelf(IgnoreAttribute)) continue;
var id = property.GetId();
dictionary[id] = new CustomViewModelInterface(id, property, @interface);
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/ViewModelGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/ViewModelGenerator.cs
index 62e26d3..0118c96 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/ViewModelGenerator.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/ViewModels/ViewModelGenerator.cs
@@ -1,26 +1,28 @@
+using System;
using System.Threading;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.ViewModels.Body;
-using Aspid.MVVM.Generators.ViewModels.Data;
-using Aspid.MVVM.Generators.ViewModels.Factories;
-using Aspid.MVVM.Generators.ViewModels.Data.Members.Collections;
+using Aspid.MVVM.Generators.Generators.ViewModels.Body;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Factories;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Members.Collections;
using Unsafe = System.Runtime.CompilerServices.Unsafe;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.ViewModels;
+namespace Aspid.MVVM.Generators.Generators.ViewModels;
[Generator(LanguageNames.CSharp)]
public sealed class ViewModelGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+ Console.WriteLine(ViewModelAttribute.FullName);
var provider = context.SyntaxProvider.ForAttributeWithMetadataName(ViewModelAttribute.FullName, SyntacticPredicate, FindViewModels)
- .Where(static foundForSourceGenerator => foundForSourceGenerator.IsNeed)
- .Select(static (foundForSourceGenerator, _) => foundForSourceGenerator.Container);
+ .Where(static foundForSourceGenerator => foundForSourceGenerator.HasValue)
+ .Select(static (foundForSourceGenerator, _) => foundForSourceGenerator!.Value);
context.RegisterSourceOutput(
source: provider,
@@ -35,35 +37,37 @@ private static bool SyntacticPredicate(SyntaxNode node, CancellationToken cancel
&& !candidate.Modifiers.Any(SyntaxKind.StaticKeyword);
}
- private static FoundForGenerator FindViewModels(GeneratorAttributeSyntaxContext context,
+ private static ViewModelData? FindViewModels(GeneratorAttributeSyntaxContext context,
CancellationToken cancellationToken)
{
- if (context.TargetSymbol is not INamedTypeSymbol symbol) return default;
+ if (context.TargetSymbol is not INamedTypeSymbol symbol) return null;
Debug.Assert(context.TargetNode is ClassDeclarationSyntax);
var candidate = Unsafe.As(context.TargetNode);
- var inheritor = symbol.HasAttributeInBases(ViewModelAttribute)
+ var inheritor = symbol.HasAnyAttributeInBases(ViewModelAttribute)
? Inheritor.Inheritor
: Inheritor.None;
-
- var bindableMembers = BindableMembersFactory.Create(symbol);
+
+ var bindableMembers = BindableMembersFactory.Create(symbol, candidate, out var propertyNotificationData);
var memberByGroups = IdLengthMemberGroup.Create(bindableMembers);
var customViewModelInterfaces = CustomViewModelInterfacesFactory.Create(symbol);
- var data = new ViewModelData(inheritor, symbol, candidate, bindableMembers, memberByGroups, customViewModelInterfaces);
- return new FoundForGenerator(data);
+ return new ViewModelData(inheritor, symbol, candidate, bindableMembers, memberByGroups, customViewModelInterfaces, propertyNotificationData);
}
private static void GenerateCode(SourceProductionContext context, ViewModelData data)
{
var declaration = data.Declaration;
var @namespace = declaration.GetNamespaceName();
- var declarationText = declaration.GetDeclarationText();
+ var declarationText = new DeclarationText(declaration);
- PropertiesBody.Generate(@namespace, data, declarationText, context);
+ BindableMembers.Generate(@namespace, data, declarationText, context);
RelayCommandBody.Generate(@namespace, data, declarationText, context);
- BindableMembersBody.Generate(@namespace, data, declarationText, context);
FindBindableMembersBody.Generate(@namespace, data, declarationText, context);
+ GeneratedPropertiesBody.Generate(@namespace, data, declarationText, context);
+ PropertyNotificationBody.Generate(@namespace, data, declarationText, context);
+ GeneratedPropertyMethodsBody.Generate(@namespace, data, declarationText, context);
+ BindableInterfaceMembersBody.Generate(@namespace, data, declarationText, context);
}
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderCachedBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderCachedBody.cs
index 1533b13..9a3bf71 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderCachedBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderCachedBody.cs
@@ -1,28 +1,25 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.Views.Data;
-using Aspid.MVVM.Generators.Views.Data.Members;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
-namespace Aspid.MVVM.Generators.Views.Body;
+namespace Aspid.MVVM.Generators.Generators.Views.Body;
public static class BinderCachedBody
{
- private const string GeneratedAttribute = General.GeneratedCodeViewAttribute;
- private static readonly string EditorBrowsableAttribute = $"[{Classes.EditorBrowsableAttribute.Global}({Classes.EditorBrowsableState.Global}.Never)]";
-
public static void Generate(
string @namespace,
in ViewDataSpan data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
if (data.MembersByType.PropertyBinders.Length + data.MembersByType.AsBinders.Length == 0) return;
var code = new CodeWriter();
- code.AppendClassBegin(@namespace, declaration)
+ code.BeginClass(@namespace, declaration)
.AppendCachedBinders(data)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
context.AddSource(declaration.GetFileName(@namespace, "CachedBinders"), code.GetSourceText());
}
@@ -43,8 +40,8 @@ private static CodeWriter AppendCachedBinders(this CodeWriter code, in ViewDataS
private static CodeWriter AppendCachedBinderMember(this CodeWriter code, in CachedBinderMember cashedBinderMember)
{
- code.AppendLine(EditorBrowsableAttribute)
- .AppendLine(GeneratedAttribute)
+ code.AppendLine(GeneratedCodeViewAttribute)
+ .AppendLine(EditorBrowsableAttributeNever)
.AppendLine($"private {cashedBinderMember.Type?.ToDisplayStringGlobal()} {cashedBinderMember.CachedName};")
.AppendLine();
@@ -53,8 +50,8 @@ private static CodeWriter AppendCachedBinderMember(this CodeWriter code, in Cach
private static CodeWriter AppendAsBinderMember(this CodeWriter code, AsBinderMember asBinderMember)
{
- code.AppendLine(EditorBrowsableAttribute)
- .AppendLine(GeneratedAttribute)
+ code.AppendLine(GeneratedCodeViewAttribute)
+ .AppendLine(EditorBrowsableAttributeNever)
.AppendLine(asBinderMember.Type is IArrayTypeSymbol
? $"private {asBinderMember.AsBinderType}[] {asBinderMember.CachedName};"
: $"private {asBinderMember.AsBinderType} {asBinderMember.CachedName};")
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderFieldsBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderFieldsBody.cs
new file mode 100644
index 0000000..9b03155
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/BinderFieldsBody.cs
@@ -0,0 +1,49 @@
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Aspid.Generators.Helper;
+using Aspid.Generators.Helper.Unity;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.Views.Helpers;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+
+namespace Aspid.MVVM.Generators.Generators.Views.Body;
+
+public static class BinderFieldsBody
+{
+ public static void Generate(
+ string @namespace,
+ in ViewDataSpan data,
+ DeclarationText declaration,
+ in SourceProductionContext context)
+ {
+ var virtualFields = VirtualBinderFields.Collect(data);
+ if (virtualFields.Count is 0) return;
+
+ var code = new CodeWriter();
+ code.BeginClass(@namespace, declaration);
+
+ foreach (var info in virtualFields.Values)
+ {
+ var requireBinderArgs = string.Join(", ", info.RequireBinderTypes.Select(type => $"typeof({type})"));
+
+ code.AppendLine(GeneratedCodeViewAttribute);
+
+ if (info.HeaderGroup is not null)
+ code.AppendLine($"[{Classes.HeaderGroupAttribute}({EscapeStringLiteral(info.HeaderGroup)})]");
+
+ if (info.Header is not null)
+ code.AppendLine($"[{Classes.HeaderAttribute}({EscapeStringLiteral(info.Header)})]");
+
+ code.AppendLine($"[{Classes.RequireBinderAttribute}({requireBinderArgs})]")
+ .AppendLine($"[{UnityClasses.SerializeField}] private {Classes.MonoBinder}[] {info.FieldName};")
+ .AppendLine();
+ }
+
+ code.EndClass(@namespace);
+ context.AddSource(declaration.GetFileName(@namespace, "BinderFields"), code.GetSourceText());
+ }
+
+ private static string EscapeStringLiteral(string value) =>
+ $"\"{value.Replace("\\", "\\\\").Replace("\"", "\\\"")}\"";
+}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/Extensions/BindSafelyExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/Extensions/BindSafelyExtensions.cs
index 2ea5ade..a6d8819 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/Extensions/BindSafelyExtensions.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/Extensions/BindSafelyExtensions.cs
@@ -1,33 +1,21 @@
-using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using Aspid.MVVM.Generators.Views.Data.Members;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
-namespace Aspid.MVVM.Generators.Views.Body.Extensions;
+namespace Aspid.MVVM.Generators.Generators.Views.Body.Extensions;
public static class BindSafelyExtensions
{
- public static CodeWriter AppendBindSafely(this CodeWriter code, BinderMember member, BindableMember bindableMember) =>
- code.AppendBindSafely(member, bindableMember?.GeneratedName + "Bindable");
-
+ public static CodeWriter AppendBindSafely(this CodeWriter code, BinderMember member, IBindableMemberInfo bindableMember) =>
+ code.AppendBindSafely(member, bindableMember.Bindable.PropertyName);
+
public static CodeWriter AppendBindSafely(this CodeWriter code, BinderMember member, string? bindableMemberName = null)
{
var parameters = $"new({member.Id})";
var name = member is CachedBinderMember cachedMember ? cachedMember.CachedName : member.Name;
- return code.AppendLine(bindableMemberName is not null
- ? $"{name}.BindSafely(viewModel.{bindableMemberName});"
- : $"{name}.BindSafely(viewModel.FindBindableMember({parameters}));");
-
- }
-
- private static string GetBinderMemberType(this BinderMember member)
- {
- if (member is AsBinderMember asBinderMember)
- return asBinderMember.AsBinderType;
-
- return member.Type is IArrayTypeSymbol arrayType
- ? arrayType.ElementType.ToDisplayStringGlobal()
- : member.Type.ToDisplayStringGlobal();
+ return code.AppendLine(bindableMemberName is not null
+ ? $"{name}.BindSafely(viewModel.{bindableMemberName}, this, {member.Id});"
+ : $"{name}.BindSafely(viewModel.FindBindableMember({parameters}), this, {member.Id});");
}
-}
\ No newline at end of file
+}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/GenericInitializeView.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/GenericInitializeView.cs
index b86e7dc..43e9b38 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/GenericInitializeView.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/GenericInitializeView.cs
@@ -1,33 +1,35 @@
using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
-using Aspid.MVVM.Generators.Views.Data;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.ViewModels.Factories;
-using Aspid.MVVM.Generators.Views.Body.Extensions;
-using Aspid.MVVM.Generators.ViewModels.Data.Members;
-using static Aspid.MVVM.Generators.Descriptions.Classes;
-using static Aspid.MVVM.Generators.Descriptions.Defines;
-using static Aspid.MVVM.Generators.Descriptions.General;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.Descriptions;
+using Aspid.MVVM.Generators.Generators.Views.Helpers;
+using Aspid.MVVM.Generators.Generators.ViewModels.Factories;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Aspid.MVVM.Generators.Generators.Views.Body.Extensions;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.Generators.Helper.Unity.UnityClasses;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Defines;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
-namespace Aspid.MVVM.Generators.Views.Body;
+namespace Aspid.MVVM.Generators.Generators.Views.Body;
public static class GenericInitializeView
{
public static void Generate(
string @namespace,
in ViewDataSpan data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
foreach (var genericView in data.GenericViews)
{
var code = new CodeWriter();
- code.AppendClassBegin([Namespaces.Aspid_MVVM], @namespace, declaration, null)
+ code.BeginClass([Namespaces.Aspid_MVVM], @namespace, declaration, null)
.AppendGenericViews(data, genericView)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
context.AddSource(declaration.GetFileName(@namespace, genericView.Type.ToDisplayString()), code.GetSourceText());
}
@@ -97,12 +99,12 @@ public void Initialize({{typeName}} viewModel)
if (genericView.Type.TypeKind is not TypeKind.Interface)
{
- var bindableMembers = new Dictionary();
+ var bindableMembers = new Dictionary();
for (var viewModelType = genericView.Type; viewModelType is not null; viewModelType = viewModelType.BaseType)
{
foreach (var memberPair in
- BindableMembersFactory.Create(viewModelType)
+ BindableMembersFactory.Create(viewModelType, data.Declaration, out _)
.ToDictionary(bindable => bindable.Id.SourceValue, bindable => bindable))
{
bindableMembers.Add(memberPair.Key, memberPair.Value);
@@ -120,6 +122,13 @@ public void Initialize({{typeName}} viewModel)
code.AppendBindSafely(member);
}
}
+
+ var virtualFields = VirtualBinderFields.Collect(data);
+ foreach (var info in virtualFields.Values)
+ {
+ if (bindableMembers.TryGetValue(info.Id.SourceValue, out var bindableMember))
+ code.AppendLine($"{info.FieldName}.BindSafely(viewModel.{bindableMember.Bindable.PropertyName}, this, {info.Id.Value});");
+ }
}
else
{
@@ -156,7 +165,7 @@ private static CodeWriter AppendProfilerMarker(this CodeWriter code, in ViewData
$"""
#if !{ASPID_MVVM_UNITY_PROFILER_DISABLED}
{GeneratedCodeViewAttribute}
- [{EditorBrowsableAttribute}({EditorBrowsableState}.Never)]
+ {EditorBrowsableAttributeNever}
private readonly static {ProfilerMarker} __initialize{viewModelTypeName.Replace(".", "_")}Marker = new("{data.Declaration.Identifier.Text}.{viewModelTypeName}.Initialize");
#endif
""");
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/InitializeBody.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/InitializeBody.cs
index 00440c9..b9d5c9f 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/InitializeBody.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Body/InitializeBody.cs
@@ -1,35 +1,33 @@
-using System;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Views.Data;
-using Aspid.MVVM.Generators.Descriptions;
-using Aspid.MVVM.Generators.Views.Data.Members;
-using Aspid.MVVM.Generators.Views.Body.Extensions;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.Descriptions;
+using Aspid.MVVM.Generators.Generators.Views.Helpers;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
+using Aspid.MVVM.Generators.Generators.Views.Body.Extensions;
+using static Aspid.Generators.Helper.Classes;
+using static Aspid.Generators.Helper.Unity.UnityClasses;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using static Aspid.MVVM.Generators.Generators.Descriptions.Constants;
-namespace Aspid.MVVM.Generators.Views.Body;
+namespace Aspid.MVVM.Generators.Generators.Views.Body;
// ReSharper disable InconsistentNaming
// ReSharper disable once InconsistentNaming
public static class InitializeBody
{
- private const string GeneratedAttribute = General.GeneratedCodeViewAttribute;
-
- private static readonly string IViewModel = Classes.IViewModel.Global;
- private static readonly string ProfilerMarker = Classes.ProfilerMarker.Global;
- private static readonly string EditorBrowsableAttribute = $"[{Classes.EditorBrowsableAttribute.Global}({Classes.EditorBrowsableState.Global}.Never)]";
-
public static void Generate(
string @namespace,
in ViewDataSpan data,
- in DeclarationText declaration,
+ DeclarationText declaration,
in SourceProductionContext context)
{
var code = new CodeWriter();
var baseTypes = GetBaseTypes(data);
- code.AppendClassBegin([Namespaces.Aspid_MVVM], @namespace, declaration, baseTypes)
+ code.BeginClass([Namespaces.Aspid_MVVM], @namespace, declaration, baseTypes)
.AppendIView(data)
- .AppendClassEnd(@namespace);
+ .EndClass(@namespace);
context.AddSource(declaration.GetFileName(@namespace, "Initialize"), code.GetSourceText());
}
@@ -40,7 +38,7 @@ private static CodeWriter AppendIView(this CodeWriter code, in ViewDataSpan data
{
Inheritor.None => code.AppendNone(data),
Inheritor.InheritorViewAttribute => code.AppendHasInterfaceOrInheritor(data),
- _ => throw new ArgumentOutOfRangeException()
+ _ => code
};
if (!data.IsInstantiateBinders) return code;
@@ -61,35 +59,35 @@ private static CodeWriter AppendNone(this CodeWriter code, in ViewDataSpan data)
.AppendMultiline(
$"""
[global::System.NonSerialized]
- {GeneratedAttribute}
- {EditorBrowsableAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private bool __isInitializing;
""")
.AppendMultilineIf(data.IsInstantiateBinders,
$"""
[global::System.NonSerialized]
- {GeneratedAttribute}
- {EditorBrowsableAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private bool __isBindersCached;
""")
.AppendMultiline(
$$"""
- {{GeneratedAttribute}}
+ {{GeneratedCodeViewAttribute}}
public {{IViewModel}} ViewModel { get; protected set; }
- {{GeneratedAttribute}}
+ {{GeneratedCodeViewAttribute}}
public void Initialize({{IViewModel}} viewModel)
{
- if (viewModel is null) throw new {{Classes.ArgumentNullException.Global}}(nameof(viewModel));
- if (ViewModel is not null) throw new {{Classes.InvalidOperationException.Global}}("View is already initialized.");
+ if (viewModel is null) throw new {{ArgumentNullException}}(nameof(viewModel));
+ if (ViewModel is not null) throw new {{InvalidOperationException}}("View is already initialized.");
ViewModel = viewModel;
InitializeInternal(viewModel);
}
- {{GeneratedAttribute}}
+ {{GeneratedCodeViewAttribute}}
{{modifiers}} void InitializeInternal({{IViewModel}} viewModel)
""")
.AppendInitializeBody(data)
@@ -97,7 +95,7 @@ public void Initialize({{IViewModel}} viewModel)
.AppendLine()
.AppendMultiline(
$$"""
- {{GeneratedAttribute}}
+ {{GeneratedCodeViewAttribute}}
public void Deinitialize()
{
if (ViewModel is null) return;
@@ -106,7 +104,7 @@ public void Deinitialize()
ViewModel = null;
}
- {{GeneratedAttribute}}
+ {{GeneratedCodeViewAttribute}}
{{modifiers}} void DeinitializeInternal()
""")
.AppendDeinitializeBody(data)
@@ -125,16 +123,16 @@ private static CodeWriter AppendHasInterfaceOrInheritor(this CodeWriter code, in
.AppendMultiline(
$"""
[global::System.NonSerialized]
- {GeneratedAttribute}
- {EditorBrowsableAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private bool __isInitializing;
""")
.AppendMultilineIf(data.IsInstantiateBinders,
$"""
[global::System.NonSerialized]
- {GeneratedAttribute}
- {EditorBrowsableAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private bool __isBindersCached;
""");
@@ -156,12 +154,12 @@ private static CodeWriter AppendProfilerMarkers(this CodeWriter code, string cla
return code.AppendMultiline(
$"""
#if !{Defines.ASPID_MVVM_UNITY_PROFILER_DISABLED}
- {EditorBrowsableAttribute}
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private static readonly {ProfilerMarker} __initializeMarker = new("{className}.Initialize");
- {EditorBrowsableAttribute}
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
+ {EditorBrowsableAttributeNever}
private static readonly {ProfilerMarker} __deinitializeMarker = new("{className}.Deinitialize");
#endif
""");
@@ -175,7 +173,7 @@ private static CodeWriter AppendInitializeInternalDeclaration(this CodeWriter co
code.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
{modifiers} void InitializeInternal({IViewModel} viewModel)
""");
@@ -190,7 +188,7 @@ private static CodeWriter AppendDeinitializeInternalDeclaration(this CodeWriter
code.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
{modifiers} void DeinitializeInternal()
""");
@@ -236,7 +234,11 @@ private static CodeWriter AppendInitializeBody(this CodeWriter code, in ViewData
foreach (var member in data.Members)
code.AppendBindSafely(member);
-
+
+ var virtualFields = VirtualBinderFields.Collect(data);
+ foreach (var info in virtualFields.Values)
+ code.AppendLine($"{info.FieldName}.BindSafely(viewModel.FindBindableMember(new({info.Id.Value})), this, {info.Id.Value});");
+
return code.AppendLine()
.AppendLine("OnInitializedInternal(viewModel);")
.AppendLine("__isInitializing = false;")
@@ -263,14 +265,18 @@ private static CodeWriter AppendDeinitializeBody(this CodeWriter code, in ViewDa
{
if (member is CachedBinderMember cachedBinderMember)
{
- code.AppendLine($"{cachedBinderMember.CachedName}.UnbindSafely();");
+ code.AppendLine($"{cachedBinderMember.CachedName}.UnbindSafely(this, {member.Id});");
}
else
{
- code.AppendLine($"{member.Name}.UnbindSafely();");
+ code.AppendLine($"{member.Name}.UnbindSafely(this, {member.Id});");
}
}
+ var virtualFields = VirtualBinderFields.Collect(data);
+ foreach (var info in virtualFields.Values)
+ code.AppendLine($"{info.FieldName}.UnbindSafely(this, {info.Id.Value});");
+
code.AppendLine()
.AppendLine("OnDeinitializedInternal();")
.EndBlock()
@@ -283,7 +289,7 @@ private static CodeWriter AppendInstantiateBindersMethods(this CodeWriter code,
{
code.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
private void InstantiateBinders()
""")
.BeginBlock()
@@ -298,10 +304,10 @@ private void InstantiateBinders()
.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnInstantiatingBinders();
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnInstantiatedBinders();
""");
@@ -341,12 +347,12 @@ private static CodeWriter AppendCreateBinders(this CodeWriter code, in ViewDataS
code.AppendLineIf(isAppend)
.AppendMultiline(
- $$"""
- var {{localName}} = {{name}};
- {{binderName}} = new {{binderType}}[{{localName}}.Length];
+ $"""
+ var {localName} = {name};
+ {binderName} = new {binderType}[{localName}.Length];
- for (var i = 0; i < {{localName}}.Length; i++)
- {{binderName}}[i] = new {{member.AsBinderType}}({{localName}}[i]{{arguments}});
+ for (var i = 0; i < {localName}.Length; i++)
+ {binderName}[i] = new {member.AsBinderType}({localName}[i]{arguments});
""")
.AppendLineIf(i + 1 < membersCount);
@@ -368,10 +374,10 @@ private static CodeWriter AppendInitializeInternalEvents(this CodeWriter code)
return code.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnInitializingInternal({IViewModel} viewModel);
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnInitializedInternal({IViewModel} viewModel);
""");
}
@@ -381,14 +387,14 @@ private static CodeWriter AppendDeinitializeInternalEvents(this CodeWriter code)
return code.AppendMultiline(
$"""
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnDeinitializingInternal();
- {GeneratedAttribute}
+ {GeneratedCodeViewAttribute}
partial void OnDeinitializedInternal();
""");
}
private static string[]? GetBaseTypes(in ViewDataSpan data) =>
- data.Inheritor is Inheritor.None ? [Classes.IView.ToString()] : null;
+ data.Inheritor is Inheritor.None ? [IView.ToString()] : null;
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/GenericViewData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/GenericViewData.cs
index 66625af..386bc02 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/GenericViewData.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/GenericViewData.cs
@@ -1,7 +1,7 @@
using System;
using Microsoft.CodeAnalysis;
-namespace Aspid.MVVM.Generators.Views.Data;
+namespace Aspid.MVVM.Generators.Generators.Views.Data;
public readonly struct GenericViewData(bool isSelf, ITypeSymbol type) : IEquatable
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Inheritor.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Inheritor.cs
index f34b095..9a4d9bd 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Inheritor.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Inheritor.cs
@@ -1,7 +1,7 @@
-namespace Aspid.MVVM.Generators.Views.Data;
+namespace Aspid.MVVM.Generators.Generators.Views.Data;
public enum Inheritor
{
None,
InheritorViewAttribute,
-}
+}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/AsBinderMember.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/AsBinderMember.cs
index 4960011..9a3d2c4 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/AsBinderMember.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/AsBinderMember.cs
@@ -1,7 +1,7 @@
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
-namespace Aspid.MVVM.Generators.Views.Data.Members;
+namespace Aspid.MVVM.Generators.Generators.Views.Data.Members;
public class AsBinderMember(ISymbol member, string asBinderType, IReadOnlyList? arguments) : CachedBinderMember(member)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/BinderMember.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/BinderMember.cs
index ff9ff22..a1d676c 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/BinderMember.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/BinderMember.cs
@@ -1,8 +1,8 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Ids.Data;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
-namespace Aspid.MVVM.Generators.Views.Data.Members;
+namespace Aspid.MVVM.Generators.Generators.Views.Data.Members;
public class BinderMember
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/CachedBinderMember.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/CachedBinderMember.cs
index 1bfa836..9c65a86 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/CachedBinderMember.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/CachedBinderMember.cs
@@ -1,7 +1,7 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.MVVM.Generators.Helpers;
-namespace Aspid.MVVM.Generators.Views.Data.Members;
+namespace Aspid.MVVM.Generators.Generators.Views.Data.Members;
public class CachedBinderMember(ISymbol member) : BinderMember(member)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/Collections/BinderMembersCollectionSpanByType.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/Collections/BinderMembersCollectionSpanByType.cs
index e6cfbbe..26b65fb 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/Collections/BinderMembersCollectionSpanByType.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/Members/Collections/BinderMembersCollectionSpanByType.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
-using Aspid.Generator.Helpers;
using System.Collections.Immutable;
+using Aspid.MVVM.Generators.Helpers;
-namespace Aspid.MVVM.Generators.Views.Data.Members.Collections;
+namespace Aspid.MVVM.Generators.Generators.Views.Data.Members.Collections;
public readonly ref struct BinderMembersCollectionSpanByType
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewData.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewData.cs
index cccc8d3..4186338 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewData.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewData.cs
@@ -1,20 +1,22 @@
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.Views.Data.Members;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
-namespace Aspid.MVVM.Generators.Views.Data;
+namespace Aspid.MVVM.Generators.Generators.Views.Data;
public readonly struct ViewData(
INamedTypeSymbol symbol,
- Inheritor inheritor,
+ Inheritor inheritor,
TypeDeclarationSyntax declaration,
ImmutableArray members,
- ImmutableArray genericViews)
+ ImmutableArray genericViews,
+ ImmutableArray inheritedDeclaredIds)
{
- public readonly INamedTypeSymbol Symbol = symbol;
+ public readonly INamedTypeSymbol Symbol = symbol;
public readonly Inheritor Inheritor = inheritor;
public readonly ImmutableArray Members = members;
public readonly TypeDeclarationSyntax Declaration = declaration;
public readonly ImmutableArray GenericViews = genericViews;
+ public readonly ImmutableArray InheritedDeclaredIds = inheritedDeclaredIds;
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewDataSpan.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewDataSpan.cs
index 0eb1720..0c567ea 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewDataSpan.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Data/ViewDataSpan.cs
@@ -1,10 +1,10 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.Views.Data.Members;
-using Aspid.MVVM.Generators.Views.Data.Members.Collections;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members.Collections;
-namespace Aspid.MVVM.Generators.Views.Data;
+namespace Aspid.MVVM.Generators.Generators.Views.Data;
public readonly ref struct ViewDataSpan(ViewData viewData)
{
@@ -14,6 +14,7 @@ public readonly ref struct ViewDataSpan(ViewData viewData)
public readonly ReadOnlySpan Members = viewData.Members.AsSpan();
public readonly BinderMembersCollectionSpanByType MembersByType = new(viewData.Members);
public readonly ReadOnlySpan GenericViews = viewData.GenericViews.AsSpan();
+ public readonly ReadOnlySpan InheritedDeclaredIds = viewData.InheritedDeclaredIds.AsSpan();
public bool IsInstantiateBinders => MembersByType.AsBinders.Length + MembersByType.PropertyBinders.Length > 0;
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Factories/BinderMembersFactory.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Factories/BinderMembersFactory.cs
index 7e4bdca..fa3c1a3 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Factories/BinderMembersFactory.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Factories/BinderMembersFactory.cs
@@ -1,34 +1,49 @@
using System.Linq;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp;
-using Aspid.MVVM.Generators.Descriptions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.Views.Data.Members;
+using Aspid.MVVM.Generators.Generators.Views.Data.Members;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.Views.Factories;
+namespace Aspid.MVVM.Generators.Generators.Views.Factories;
public static class BinderMembersFactory
{
+ public static ImmutableArray CollectInheritedIds(INamedTypeSymbol symbol, SemanticModel semanticModel)
+ {
+ var ids = ImmutableArray.CreateBuilder();
+
+ for (var baseType = symbol.BaseType; baseType is not null; baseType = baseType.BaseType)
+ {
+ if (!baseType.HasAnyAttributeInSelf(Classes.ViewAttribute)) continue;
+
+ foreach (var member in Create(baseType, semanticModel))
+ ids.Add(member.Id.SourceValue);
+ }
+
+ return ids.ToImmutable();
+ }
+
public static ImmutableArray Create(INamedTypeSymbol symbolClass, SemanticModel semanticModel)
{
var binderMembers = new List();
foreach (var member in symbolClass.GetMembers())
{
- if (member.HasAnyAttribute(Classes.IgnoreAttribute)) continue;
+ if (member.HasAnyAttributeInSelf()) continue;
var type = GetType(member);
if (type is null) continue;
- if (member.HasAnyAttribute(out var asBinderAttribute, Classes.AsBinderAttribute))
+ if (member.TryGetAnyAttributeInSelf(out var asBinderAttribute, Classes.AsBinderAttribute))
{
if (asBinderAttribute!.ConstructorArguments[0].Value is not INamedTypeSymbol argumentType) continue;
if (argumentType.IsAbstract) continue;
- if (!argumentType.HasInterfaceInSelfOrBases(Classes.IBinder)) continue;
+ if (!argumentType.HasAnyInterfaceInSelfAndBases(Classes.IBinder)) continue;
var arguments = new List();
@@ -93,11 +108,11 @@ invocationExpression.Expression is IdentifierNameSyntax identifier &&
binderMembers.Add(new AsBinderMember(member, argumentType.ToDisplayStringGlobal(), arguments));
}
- else if (type.HasAnyAttribute(Classes.ViewAttribute) || type.HasInterfaceInSelfOrBases(Classes.IView))
+ else if (type.HasAnyAttributeInSelf(Classes.ViewAttribute) || type.HasAnyInterfaceInSelfAndBases(Classes.IView))
{
- binderMembers.Add(new AsBinderMember(member, Classes.ViewBinder.Global, null));
+ binderMembers.Add(new AsBinderMember(member, Classes.ViewBinder, null));
}
- else if (type.HasInterfaceInSelfOrBases(Classes.IBinder))
+ else if (type.HasAnyInterfaceInSelfAndBases(Classes.IBinder))
{
switch (member)
{
@@ -110,7 +125,7 @@ invocationExpression.Expression is IdentifierNameSyntax identifier &&
var symbols = GetPropertyReturnSymbols(property, semanticModel);
if (symbols is null) continue;
- if (symbols.Any(symbol => symbol is IFieldSymbol or IPropertySymbol && !symbol.HasAnyAttribute(Classes.IgnoreAttribute))) continue;
+ if (symbols.Any(symbol => symbol is IFieldSymbol or IPropertySymbol && !symbol.HasAnyAttributeInSelf(Classes.IgnoreAttribute))) continue;
binderMembers.Add(new CachedBinderMember(property));
break;
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Helpers/VirtualBinderFields.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Helpers/VirtualBinderFields.cs
new file mode 100644
index 0000000..0c212b4
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/Helpers/VirtualBinderFields.cs
@@ -0,0 +1,177 @@
+using Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+using Aspid.Generators.Helper;
+using Aspid.Generators.Helper.Unity;
+using Aspid.MVVM.Generators.Generators.Ids.Data;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.ViewModels.Factories;
+using Aspid.MVVM.Generators.Generators.ViewModels.Data.Infos;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
+using SymbolExtensions = Aspid.MVVM.Generators.Helpers.SymbolExtensions;
+
+namespace Aspid.MVVM.Generators.Generators.Views.Helpers;
+
+public static class VirtualBinderFields
+{
+ public static Dictionary Collect(in ViewDataSpan data)
+ {
+ var result = new Dictionary();
+ if (data.GenericViews.Length == 0) return result;
+ if (!IsAutoBinderFieldsEnabled(data.Symbol)) return result;
+ if (InheritsFromScriptableObject(data.Symbol)) return result;
+
+ var declared = new HashSet();
+ foreach (var member in data.Members)
+ declared.Add(member.Id.SourceValue);
+ foreach (var id in data.InheritedDeclaredIds)
+ declared.Add(id);
+
+ foreach (var genericView in data.GenericViews)
+ {
+ if (genericView.Type.TypeKind is TypeKind.Interface) continue;
+
+ for (var viewModelType = genericView.Type; viewModelType is not null; viewModelType = viewModelType.BaseType)
+ {
+ CollectFromType(viewModelType, data, declared, result);
+ }
+ }
+
+ return result;
+ }
+
+ private static void CollectFromType(
+ ITypeSymbol viewModelType,
+ in ViewDataSpan data,
+ HashSet declared,
+ Dictionary result)
+ {
+ var bindableMembers = BindableMembersFactory.Create(viewModelType, data.Declaration, out _);
+ if (bindableMembers.Length == 0) return;
+
+ var membersBySymbol = new Dictionary>(SymbolEqualityComparer.Default);
+ foreach (var bindable in bindableMembers)
+ {
+ if (!membersBySymbol.TryGetValue(bindable.Member, out var list))
+ {
+ list = [];
+ membersBySymbol[bindable.Member] = list;
+ }
+
+ list.Add(bindable);
+ }
+
+ string? activeGroup = null;
+
+ foreach (var symbol in viewModelType.GetMembers())
+ {
+ var groupStart = GetAttributeStringArgument(symbol, Classes.HeaderGroupStartAttribute);
+ var groupName = GetAttributeStringArgument(symbol, Classes.HeaderGroupAttribute);
+ var groupEnd = HasAttribute(symbol, Classes.HeaderGroupEndAttribute);
+
+ if (groupStart is not null) activeGroup = groupStart;
+ else if (groupName is not null) activeGroup = groupName;
+
+ if (membersBySymbol.TryGetValue(symbol, out var bindablesForSymbol))
+ {
+ foreach (var bindableMember in bindablesForSymbol)
+ {
+ var sourceValue = bindableMember.Id.SourceValue;
+ if (declared.Contains(sourceValue)) continue;
+
+ if (!result.TryGetValue(sourceValue, out var info))
+ {
+ info = new Info(bindableMember.Id, SymbolExtensions.GetFieldName(sourceValue, "_"));
+ result[sourceValue] = info;
+ }
+
+ var requireType = StripNullable(bindableMember.Type);
+ if (!info.RequireBinderTypes.Contains(requireType))
+ info.RequireBinderTypes.Add(requireType);
+
+ if (bindableMember is not BindableCommandInfo)
+ info.Header ??= GetAttributeStringArgument(symbol, Classes.HeaderAttribute);
+
+ if (activeGroup is not null)
+ info.HeaderGroup ??= activeGroup;
+
+ if (groupEnd && !info.HeaderGroupEnd)
+ info.HeaderGroupEnd = true;
+ }
+ }
+
+ if (groupEnd) activeGroup = null;
+ }
+ }
+
+ private static bool IsAutoBinderFieldsEnabled(INamedTypeSymbol viewSymbol)
+ {
+ foreach (var attribute in viewSymbol.GetAttributes())
+ {
+ if (attribute.AttributeClass?.ToDisplayString() != Classes.ViewAttribute.FullName) continue;
+
+ foreach (var named in attribute.NamedArguments)
+ {
+ if (named.Key != "AutoBinderFields") continue;
+ if (named.Value.Value is bool enabled) return enabled;
+ }
+
+ return true;
+ }
+
+ return true;
+ }
+
+ private static bool InheritsFromScriptableObject(INamedTypeSymbol viewSymbol)
+ {
+ var scriptableObjectFullName = UnityClasses.ScriptableObject.FullName;
+
+ for (var type = viewSymbol.BaseType; type is not null; type = type.BaseType)
+ {
+ if (type.ToDisplayString() == scriptableObjectFullName) return true;
+ }
+
+ return false;
+ }
+
+ private static string? GetAttributeStringArgument(ISymbol symbol, AttributeText attributeText)
+ {
+ if (symbol.TryGetAnyAttributeInSelf(out var attribute, attributeText))
+ {
+ if (attribute.ConstructorArguments.Length is 0) return null;
+
+ var value = attribute.ConstructorArguments[0].Value as string;
+ if (!string.IsNullOrWhiteSpace(value)) return value;
+ }
+
+ return null;
+ }
+
+ private static bool HasAttribute(ISymbol symbol, string attributeFullName)
+ {
+ foreach (var attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass?.ToDisplayString() == attributeFullName)
+ return true;
+ }
+
+ return false;
+ }
+
+ private static string StripNullable(string type) =>
+ type.EndsWith("?") ? type.Substring(0, type.Length - 1) : type;
+
+ public sealed class Info(IdData id, string fieldName)
+ {
+ public IdData Id { get; } = id;
+
+ public string FieldName { get; } = fieldName;
+
+ public List RequireBinderTypes { get; } = [];
+
+ public string? Header { get; set; }
+
+ public string? HeaderGroup { get; set; }
+
+ public bool HeaderGroupEnd { get; set; }
+ }
+}
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Find.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Find.cs
index 10c18a9..846765f 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Find.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Find.cs
@@ -1,36 +1,36 @@
using System.Threading;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
+using Aspid.Generators.Helper;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
-using Aspid.MVVM.Generators.Views.Data;
-using Aspid.MVVM.Generators.Descriptions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Aspid.MVVM.Generators.Views.Factories;
+using Aspid.MVVM.Generators.Generators.Views.Data;
+using Aspid.MVVM.Generators.Generators.Views.Factories;
+using Classes = Aspid.MVVM.Generators.Generators.Descriptions.Classes;
-namespace Aspid.MVVM.Generators.Views;
+namespace Aspid.MVVM.Generators.Generators.Views;
public partial class ViewGenerator
{
- private static FoundForGenerator FindView(
+ private static ViewData? FindView(
GeneratorAttributeSyntaxContext context,
CancellationToken cancellationToken)
{
- if (context.TargetSymbol is not INamedTypeSymbol symbol) return default;
+ if (context.TargetSymbol is not INamedTypeSymbol symbol) return null;
- var inheritor = symbol.HasAttributeInBases(Classes.ViewAttribute)
+ var inheritor = symbol.HasAnyAttributeInBases(Classes.ViewAttribute)
? Inheritor.InheritorViewAttribute
: Inheritor.None;
var members = BinderMembersFactory.Create(symbol, context.SemanticModel);
+ var inheritedDeclaredIds = BinderMembersFactory.CollectInheritedIds(symbol, context.SemanticModel);
Debug.Assert(context.TargetNode is TypeDeclarationSyntax);
var candidate = Unsafe.As(context.TargetNode);
- var viewData = new ViewData(symbol, inheritor, candidate, members, GetGenericViews(symbol));
- return new FoundForGenerator(viewData);
+ return new ViewData(symbol, inheritor, candidate, members, GetGenericViews(symbol), inheritedDeclaredIds);
}
private static ImmutableArray GetGenericViews(INamedTypeSymbol symbol)
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Generate.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Generate.cs
index 4c78aec..79e266c 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Generate.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.Generate.cs
@@ -1,9 +1,9 @@
using Microsoft.CodeAnalysis;
-using Aspid.Generator.Helpers;
-using Aspid.MVVM.Generators.Views.Body;
-using Aspid.MVVM.Generators.Views.Data;
+using Aspid.Generators.Helper;
+using Aspid.MVVM.Generators.Generators.Views.Body;
+using Aspid.MVVM.Generators.Generators.Views.Data;
-namespace Aspid.MVVM.Generators.Views;
+namespace Aspid.MVVM.Generators.Generators.Views;
public partial class ViewGenerator
{
@@ -13,10 +13,11 @@ private static void GenerateCode(SourceProductionContext context, ViewData data)
var declaration = dataSpan.Declaration;
var @namespace = declaration.GetNamespaceName();
- var declarationText = declaration.GetDeclarationText();
+ var declarationText = new DeclarationText(declaration);
InitializeBody.Generate(@namespace, dataSpan, declarationText, context);
BinderCachedBody.Generate(@namespace, dataSpan, declarationText, context);
+ BinderFieldsBody.Generate(@namespace, dataSpan, declarationText, context);
GenericInitializeView.Generate(@namespace, dataSpan, declarationText, context);
}
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.cs
index 54b8a13..72fe30e 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Generators/Views/ViewGenerator.cs
@@ -1,10 +1,10 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
-using Aspid.MVVM.Generators.Descriptions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Aspid.MVVM.Generators.Generators.Descriptions;
-namespace Aspid.MVVM.Generators.Views;
+namespace Aspid.MVVM.Generators.Generators.Views;
[Generator(LanguageNames.CSharp)]
public partial class ViewGenerator : IIncrementalGenerator
@@ -12,8 +12,8 @@ public partial class ViewGenerator : IIncrementalGenerator
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.SyntaxProvider.ForAttributeWithMetadataName(Classes.ViewAttribute.FullName, SyntacticPredicate, FindView)
- .Where(foundForSourceGenerator => foundForSourceGenerator.IsNeed)
- .Select((foundForSourceGenerator, _) => foundForSourceGenerator.Container);
+ .Where(foundForSourceGenerator => foundForSourceGenerator.HasValue)
+ .Select((foundForSourceGenerator, _) => foundForSourceGenerator!.Value);
context.RegisterSourceOutput(
source: provider,
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/AttributeText.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/AttributeText.cs
deleted file mode 100644
index 183c698..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/AttributeText.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Aspid.Generator.Helpers;
-
-public class AttributeText(string name, NamespaceText? @namespace = null) :
- TypeText(name + "Attribute", @namespace)
-{
- public string AttributeName => name;
-
- public string AttributeFullName => (Namespace != null ? $"{Namespace}." : "") + AttributeName;
-
- public string AttributeGlobal => $"global::{AttributeFullName}";
-
- public override string ToString() =>
- AttributeGlobal;
-
- public static implicit operator string(AttributeText type) =>
- type.ToString();
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/CastedSpan.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CastedSpan.cs
similarity index 95%
rename from Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/CastedSpan.cs
rename to Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CastedSpan.cs
index 520dd1b..450eeb7 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/CastedSpan.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CastedSpan.cs
@@ -1,7 +1,7 @@
using System;
using System.Runtime.CompilerServices;
-namespace Aspid.Generator.Helpers;
+namespace Aspid.MVVM.Generators.Helpers;
public ref struct CastedSpan(ReadOnlySpan span)
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CodeWriter.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CodeWriter.cs
deleted file mode 100644
index 72c76c8..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/CodeWriter.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.CodeDom.Compiler;
-using Microsoft.CodeAnalysis.Text;
-
-namespace Aspid.Generator.Helpers;
-
-public sealed class CodeWriter
-{
- private readonly MemoryStream _sourceStream;
- private readonly IndentedTextWriter _textWriter;
-
- public int Indent
- {
- get => _textWriter.Indent;
- set => _textWriter.Indent = value;
- }
-
- public CodeWriter()
- {
- _sourceStream = new MemoryStream();
- var sourceStreamWriter = new StreamWriter(_sourceStream, Encoding.UTF8);
- _textWriter = new IndentedTextWriter(sourceStreamWriter);
- }
-
- public CodeWriter Append(string value = "")
- {
- _textWriter.Write(value);
- return this;
- }
-
- public CodeWriter AppendLine(string value = "")
- {
- _textWriter.WriteLine(value);
- return this;
- }
-
- public CodeWriter AppendMultiline(string value)
- {
- var indent = Indent;
- Indent = 0;
-
- var tab = new string('\t', indent);
- value = $"{tab}{value}";
- value = value.Replace("\n", $"\n{tab}");
- AppendLine(value);
-
- Indent = indent;
- return this;
- }
-
- public IDisposable BeginIndentScope() =>
- new IndentScope(this);
-
- public IDisposable BeginBlockScope() =>
- new BlockScope(this);
-
- public CodeWriter BeginBlock()
- {
- AppendLine("{");
- IncreaseIndent();
-
- return this;
- }
-
- public CodeWriter EndBlock()
- {
- DecreaseIndent();
- AppendLine("}");
-
- return this;
- }
-
- public CodeWriter IncreaseIndent()
- {
- _textWriter.Indent++;
- return this;
- }
-
- public CodeWriter DecreaseIndent()
- {
- _textWriter.Indent--;
- return this;
- }
-
- public SourceText GetSourceText()
- {
- _textWriter.Flush();
- return SourceText.From(_sourceStream, Encoding.UTF8, canBeEmbedded: true);
- }
-
- private readonly struct IndentScope : IDisposable
- {
- private readonly CodeWriter _source;
-
- public IndentScope(CodeWriter source)
- {
- _source = source;
- source.IncreaseIndent();
- }
-
- public void Dispose() =>
- _source.DecreaseIndent();
- }
-
- private readonly struct BlockScope : IDisposable
- {
- private readonly CodeWriter _source;
-
- public BlockScope(CodeWriter source)
- {
- _source = source;
- source.BeginBlock();
- }
-
- public void Dispose() =>
- _source.EndBlock();
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/DeclarationText.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/DeclarationText.cs
deleted file mode 100644
index 751ad04..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/DeclarationText.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Linq;
-
-namespace Aspid.Generator.Helpers;
-
-public readonly struct DeclarationText(string? modifiers, string typeType, string name, string? genericArguments)
-{
- public string? Modifiers { get; } = modifiers;
-
- public string TypeType { get; } = typeType;
-
- public string Name { get; } = name;
-
- public string? GenericArguments { get; } = genericArguments;
-
- public string GetFileName(string? namespaceName, string? postfix)
- {
- postfix ??= "";
- if (postfix.Length > 0 && postfix[0] != '.') postfix = $".{postfix}";
-
- namespaceName = string.IsNullOrEmpty(namespaceName) ? "" : $"{namespaceName}.";
-
- return namespaceName + (string.IsNullOrEmpty(GenericArguments)
- ? $"{Name}{postfix}.g.cs"
- : $"{Name}`{GenericArguments!.Count(arg => arg == ',') + 1}{postfix}.g.cs");
- }
-
- public override string ToString()
- {
- var modifiers = !string.IsNullOrEmpty(Modifiers) ? $"{Modifiers} " : "";
- var arguments = !string.IsNullOrEmpty(GenericArguments) ? $"<{GenericArguments}>" : "";
-
- return $"{modifiers}{TypeType} {Name}{arguments}";
- }
-
- public static implicit operator string(DeclarationText declaration) =>
- declaration.ToString();
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/CSharpSyntaxNodeExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/CSharpSyntaxNodeExtensions.cs
deleted file mode 100644
index 762e70b..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/CSharpSyntaxNodeExtensions.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Aspid.Generator.Helpers;
-
-public static class CSharpSyntaxNodeExtensions
-{
- public static string GetNamespaceName(this CSharpSyntaxNode node)
- {
- for (var parent = node.Parent; parent != null; parent = parent.Parent)
- {
- if (parent is BaseNamespaceDeclarationSyntax namespaceDeclaration)
- return namespaceDeclaration.Name.ToString();
- }
-
- return "";
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/MemberDeclarationSyntaxExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/MemberDeclarationSyntaxExtensions.cs
deleted file mode 100644
index 0869f7e..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/MemberDeclarationSyntaxExtensions.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Aspid.Generator.Helpers;
-
-public static class MemberDeclarationSyntaxExtensions
-{
- public static bool HasAttribute(this MemberDeclarationSyntax declaration, SemanticModel semanticModel, string name)
- {
- foreach (var attribute in declaration.AttributeLists.SelectMany(attributeList => attributeList.Attributes))
- {
- if (semanticModel.GetSymbolInfo(attribute).Symbol is not IMethodSymbol attributeSymbol) continue;
- if (attributeSymbol.ContainingType?.ToDisplayString() == name) return true;
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/PropertyDeclarationSyntaxExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/PropertyDeclarationSyntaxExtensions.cs
deleted file mode 100644
index fabb772..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/PropertyDeclarationSyntaxExtensions.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Aspid.Generator.Helpers;
-
-public static class PropertyDeclarationSyntaxExtensions
-{
- public static bool HasGetAccessor(this PropertyDeclarationSyntax property) =>
- property.HasAccessor(SyntaxKind.GetAccessorDeclaration);
-
- public static bool HasSetAccessor(this PropertyDeclarationSyntax property) =>
- property.HasAccessor(SyntaxKind.SetAccessorDeclaration);
-
- public static bool HasInitAccessor(this PropertyDeclarationSyntax property) =>
- property.HasAccessor(SyntaxKind.InitAccessorDeclaration);
-
- private static bool HasAccessor(this PropertyDeclarationSyntax propertyDeclaration, SyntaxKind accessorKind)
- {
- var accessorList = propertyDeclaration.AccessorList;
- return accessorList != null && accessorList.Accessors.Any(accessor => accessor.Kind() == accessorKind);
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/TypeDeclarationSyntaxExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/TypeDeclarationSyntaxExtensions.cs
deleted file mode 100644
index 884392c..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Declarations/TypeDeclarationSyntaxExtensions.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System.Text;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-
-namespace Aspid.Generator.Helpers;
-
-public static class TypeDeclarationSyntaxExtensions
-{
- public static DeclarationText GetDeclarationText(this TypeDeclarationSyntax declaration)
- {
- var modifiers = declaration.GetModifiersAsText();
- var typeType = declaration is ClassDeclarationSyntax ? "class" : "struct";
- var typeName = declaration.Identifier.Text;
- var genericArguments = declaration.GetGenericArgumentsAsText();
-
- return new DeclarationText(modifiers, typeType, typeName, genericArguments);
- }
-
- private static string GetModifiersAsText(this TypeDeclarationSyntax declaration)
- {
- var modifiers = new StringBuilder();
- foreach (var modifier in declaration.Modifiers)
- modifiers.Append(modifier.ToString() + " ");
-
- modifiers.Length--;
- return modifiers.ToString();
- }
-
- private static string GetGenericArgumentsAsText(this TypeDeclarationSyntax declaration)
- {
- var types = declaration.TypeParameterList;
- if (types == null || types.Parameters.Count == 0) return "";
-
- var genericTypes = new StringBuilder();
- foreach (var type in types.Parameters)
- {
- if (genericTypes.Length > 0)
- genericTypes.Append(", ");
-
- genericTypes.Append(type.Identifier.Text);
- }
-
- return genericTypes.ToString();
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/MethodSymbolExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/MethodSymbolExtensions.cs
deleted file mode 100644
index 3ed60a4..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/MethodSymbolExtensions.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis;
-
-namespace Aspid.Generator.Helpers;
-
-public static class MethodSymbolExtensions
-{
- public static bool EqualsSignature(this IMethodSymbol method1, IMethodSymbol method2)
- {
- if (method1.Parameters.Length != method2.Parameters.Length) return false;
-
- var method1Name = method1.NameFromExplicitImplementation();
- var method2Name = method2.NameFromExplicitImplementation();
- if (method1Name != method2Name) return false;
-
- if (!SymbolEqualityComparer.Default.Equals(method1.ReturnType, method2.ReturnType)) return false;
-
- var areParametersEqual = method1.Parameters
- .Where((parameter, i) => SymbolEqualityComparer.Default.Equals(parameter.Type, method2.Parameters[i].Type))
- .Any();
-
- return areParametersEqual;
- }
-
- public static string NameFromExplicitImplementation(this IMethodSymbol method) =>
- method.Name.Substring(method.Name.LastIndexOf('.') + 1);
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.Attribute.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.Attribute.cs
deleted file mode 100644
index 4eed3fd..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.Attribute.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis;
-using System.Collections.Generic;
-
-namespace Aspid.Generator.Helpers;
-
-public static partial class SymbolExtensions
-{
- public static bool HasAnyAttribute(this ISymbol symbol, params IReadOnlyCollection attributeText) =>
- symbol.HasAnyAttribute(attributeText.Select(attribute => attribute.FullName).ToArray());
-
- public static bool HasAnyAttribute(this ISymbol symbol, params IReadOnlyCollection attributeFullName)
- {
- foreach (var attribute in symbol.GetAttributes())
- {
- if (attribute.AttributeClass != null && attributeFullName.Any(name => name == attribute.AttributeClass.ToDisplayString()))
- return true;
- }
-
- return false;
- }
-
- public static bool HasAnyAttribute(this ISymbol symbol, out AttributeData? foundAttribute, params IReadOnlyCollection attributeText) =>
- symbol.HasAnyAttribute(out foundAttribute, attributeText.Select(attribute => attribute.FullName).ToArray());
-
- public static bool HasAnyAttribute(this ISymbol symbol, out AttributeData? foundAttribute, params IReadOnlyCollection attributeFullName)
- {
- foundAttribute = null;
-
- foreach (var attribute in symbol.GetAttributes())
- {
- if (attribute.AttributeClass != null && attributeFullName.Any(name => name == attribute.AttributeClass.ToDisplayString()))
- {
- foundAttribute = attribute;
- return true;
- }
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Attribute.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Attribute.cs
deleted file mode 100644
index eb6d80f..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Attribute.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Microsoft.CodeAnalysis;
-
-namespace Aspid.Generator.Helpers;
-
-public static partial class TypeSymbolExtensions
-{
- public static bool HasAttributeInBases(this ITypeSymbol typeSymbol, AttributeText attributeText) =>
- HasAttributeInBases(typeSymbol, attributeText.FullName);
-
- public static bool HasAttributeInBases(this ITypeSymbol symbol, string fullName)
- {
- for (var type = symbol.BaseType; type is not null; type = type.BaseType)
- {
- if (type.HasAnyAttribute(fullName))
- return true;
- }
-
- return false;
- }
-
- public static bool HasAttributeInBases(this ITypeSymbol typeSymbol, AttributeText attributeText, out AttributeData? attribute) =>
- HasAttributeInBases(typeSymbol, attributeText.FullName, out attribute);
-
- public static bool HasAttributeInBases(this ITypeSymbol symbol, string fullName, out AttributeData? attribute)
- {
- for (var type = symbol.BaseType; type is not null; type = type.BaseType)
- {
- if (type.HasAnyAttribute(out attribute, fullName))
- return true;
- }
-
- attribute = null;
- return false;
- }
-
- public static bool HasAttributeInSelfOrBases(this ITypeSymbol typeSymbol, AttributeText attributeText) =>
- HasAttributeInSelfOrBases(typeSymbol, attributeText.FullName);
-
- public static bool HasAttributeInSelfOrBases(this ITypeSymbol symbol, string fullName)
- {
- for (var type = symbol; type is not null; type = type.BaseType)
- {
- if (type.HasAnyAttribute(fullName))
- return true;
- }
-
- return false;
- }
-
- public static bool HasAttributeInSelfOrBases(this ITypeSymbol typeSymbol, AttributeText attributeText, out AttributeData? attribute) =>
- HasAttributeInSelfOrBases(typeSymbol, attributeText.FullName, out attribute);
-
- public static bool HasAttributeInSelfOrBases(this ITypeSymbol symbol, string fullName, out AttributeData? attribute)
- {
- for (var type = symbol; type is not null; type = type.BaseType)
- {
- if (type.HasAnyAttribute(out attribute, fullName))
- return true;
- }
-
- attribute = null;
- return false;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.BaseType.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.BaseType.cs
deleted file mode 100644
index f2a18e9..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.BaseType.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis;
-
-namespace Aspid.Generator.Helpers;
-
-public static partial class TypeSymbolExtensions
-{
- public static bool HasBaseType(this ITypeSymbol symbol, TypeText typeText) =>
- HasBaseType(symbol, typeText.FullName);
-
- public static bool HasBaseType(this ITypeSymbol symbol, string baseTypeName) =>
- HasBaseType(symbol, baseTypeName, out _);
-
- public static bool HasBaseType(this ITypeSymbol symbol, TypeText typeText, out ITypeSymbol? foundBaseType) =>
- HasBaseType(symbol, typeText.FullName, out foundBaseType);
-
- public static bool HasBaseType(this ITypeSymbol symbol, string baseTypeName, out ITypeSymbol? foundBaseType)
- {
- foundBaseType = null;
-
- for (var type = symbol; type != null; type = type.BaseType)
- {
- if (type.ToDisplayString() != baseTypeName) continue;
-
- foundBaseType = type;
- return true;
- }
-
- return false;
- }
-
- public static bool HasBaseType(this ITypeSymbol symbol, params TypeText[] baseTypeNames) =>
- HasBaseType(symbol, baseTypeNames.Select(baseTypeName => baseTypeName.FullName).ToArray());
-
- public static bool HasBaseType(this ITypeSymbol symbol, params string[] baseTypeNames)
- {
- for (var type = symbol; type != null; type = type.BaseType)
- {
- if (baseTypeNames.Any(baseTypeName => type.ToDisplayString() == baseTypeName))
- {
- return true;
- }
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Interface.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Interface.cs
deleted file mode 100644
index 5bbbf87..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/TypeSymbolExtensions.Interface.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System.Linq;
-using Microsoft.CodeAnalysis;
-
-namespace Aspid.Generator.Helpers;
-
-public static partial class TypeSymbolExtensions
-{
- public static bool HasInterface(this ITypeSymbol type, TypeText typeText) =>
- type.HasInterface(typeText.FullName);
-
- public static bool HasInterface(this ITypeSymbol type, string name) =>
- type.HasInterface(name, out _);
-
- public static bool HasInterface(this ITypeSymbol type, TypeText typeText, out INamedTypeSymbol? foundInterface) =>
- type.HasInterface(typeText.FullName, out foundInterface);
-
- public static bool HasInterface(this ITypeSymbol type, string name, out INamedTypeSymbol? foundInterface)
- {
- foundInterface = null;
-
- foreach (var @interface in type.Interfaces)
- {
- if (@interface.ToDisplayString() != name) continue;
-
- foundInterface = @interface;
- return true;
- }
-
- return false;
- }
-
- public static bool HasInterfaceInBases(this ITypeSymbol type, TypeText typeText) =>
- type.HasInterfaceInBases(typeText.FullName);
-
- public static bool HasInterfaceInBases(this ITypeSymbol type, string name) =>
- type.HasInterfaceInBases(name, out _);
-
- public static bool HasInterfaceInBases(this ITypeSymbol type, TypeText typeText, out INamedTypeSymbol? foundInterface) =>
- type.HasInterfaceInBases(typeText.FullName, out foundInterface);
-
- public static bool HasInterfaceInBases(this ITypeSymbol type, string name, out INamedTypeSymbol? foundInterface)
- {
- foundInterface = null;
-
- var baseType = type.BaseType;
- if (baseType is null) return false;
-
- foreach (var @interface in baseType.AllInterfaces)
- {
- if (@interface.ToDisplayString() != name) continue;
-
- foundInterface = @interface;
- return true;
- }
-
- return false;
- }
-
- public static bool HasInterfaceInSelfOrBases(this ITypeSymbol type, TypeText typeText) =>
- type.HasInterfaceInSelfOrBases(typeText.FullName);
-
- public static bool HasInterfaceInSelfOrBases(this ITypeSymbol type, string name) =>
- type.AllInterfaces.Any(@interface => @interface.ToDisplayString() == name);
-
- public static bool HasInterfaceInSelfOrBases(this ITypeSymbol type, TypeText typeText, out INamedTypeSymbol? foundInterface) =>
- type.HasInterfaceInSelfOrBases(typeText.FullName, out foundInterface);
-
- public static bool HasInterfaceInSelfOrBases(this ITypeSymbol type, string name, out INamedTypeSymbol? foundInterface)
- {
- foundInterface = null;
-
- foreach (var @interface in type.AllInterfaces)
- {
- if (@interface.ToDisplayString() != name) continue;
-
- foundInterface = @interface;
- return true;
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteClassExtension.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteClassExtension.cs
deleted file mode 100644
index 24f5e36..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteClassExtension.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-
-namespace Aspid.Generator.Helpers;
-
-public static class CodeWriteClassExtension
-{
- public static CodeWriter AppendClass(
- this CodeWriter code,
- string @namespace,
- DeclarationText declaration,
- Action? body, params string[]? baseTypes)
- {
- code.AppendClassBegin(@namespace, declaration, baseTypes);
- body?.Invoke();
- code.AppendClassEnd(@namespace);
-
- return code;
- }
-
- public static CodeWriter AppendClassBegin(
- this CodeWriter code,
- string? @namespace,
- DeclarationText declaration,
- params string[]? baseTypes)
- {
- var hasNamespace = !string.IsNullOrEmpty(@namespace);
-
- var baseTypesText = "";
- if (baseTypes is { Length: > 0 }) baseTypesText = $" : {string.Join(",", baseTypes!)}";
-
- code.AppendLine("// ")
- .AppendChildIf(hasNamespace, () => code
- .AppendLine($"namespace {@namespace}")
- .BeginBlock())
- .AppendLine($"{declaration}{baseTypesText}")
- .BeginBlock();
-
- return code;
- }
-
- public static CodeWriter AppendClassBegin(
- this CodeWriter code,
- string[] imports,
- string? @namespace,
- DeclarationText declaration,
- params string[]? baseTypes)
- {
- var hasNamespace = !string.IsNullOrEmpty(@namespace);
-
- var baseTypesText = "";
- if (baseTypes is { Length: > 0 }) baseTypesText = $" : {string.Join(", ", baseTypes!)}";
-
- code.AppendLine("// ")
- .AppendLine()
- .AppendLoop(imports, import =>
- {
- code.AppendLine($"using {import};");
- })
- .AppendLine()
- .AppendChildIf(hasNamespace, () => code
- .AppendLine($"namespace {@namespace}")
- .BeginBlock())
- .AppendLine($"{declaration}{baseTypesText}")
- .BeginBlock();
-
- return code;
- }
-
- public static CodeWriter AppendClassEnd(this CodeWriter code, string? @namespace)
- {
- code.AppendClassEnd(!string.IsNullOrEmpty(@namespace));
- return code;
- }
-
- private static CodeWriter AppendClassEnd(this CodeWriter code, bool hasNamespace)
- {
- code.EndBlock()
- .EndBlockIf(hasNamespace);
- return code;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteLoopExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteLoopExtensions.cs
deleted file mode 100644
index f3390bb..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriteLoopExtensions.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Aspid.Generator.Helpers;
-
-public static class CodeWriteLoopExtensions
-{
- public static CodeWriter AppendLoop(this CodeWriter code, IEnumerable enumerable, Action setValue)
- {
- foreach (var value in enumerable)
- setValue(value);
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, IEnumerable enumerable, Action setValue)
- {
- var i = 0;
-
- foreach (var value in enumerable)
- {
- setValue(i, value);
- i++;
- }
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, IEnumerable enumerable, Action setValue)
- {
- foreach (var value in enumerable)
- setValue(code, value);
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, IEnumerable enumerable, Action setValue)
- {
- var i = 0;
-
- foreach (var value in enumerable)
- {
- setValue(code, i, value);
- i++;
- }
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, ReadOnlySpan span, Action setValue)
- {
- foreach (var value in span)
- setValue(value);
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, ReadOnlySpan span, Action setValue)
- {
- var i = 0;
-
- foreach (var value in span)
- {
- setValue(i, value);
- i++;
- }
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, ReadOnlySpan span, Action setValue)
- {
- foreach (var value in span)
- setValue(code, value);
-
- return code;
- }
-
- public static CodeWriter AppendLoop(this CodeWriter code, ReadOnlySpan span, Action setValue)
- {
- var i = 0;
-
- foreach (var value in span)
- {
- setValue(code, i, value);
- i++;
- }
-
- return code;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriterIfExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriterIfExtensions.cs
deleted file mode 100644
index 54346be..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Writer/CodeWriterIfExtensions.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-
-namespace Aspid.Generator.Helpers;
-
-public static class CodeWriterIfExtensions
-{
- public static CodeWriter AppendIf(this CodeWriter code, Func condition, string value = "") =>
- code.AppendIf(condition.Invoke(), value);
-
- public static CodeWriter AppendIf(this CodeWriter code, bool flag, string value = "") =>
- !flag ? code : code.Append(value);
-
- public static CodeWriter AppendLineIf(this CodeWriter code, Func condition, string value = "") =>
- code.AppendLineIf(condition.Invoke(), value);
-
- public static CodeWriter AppendLineIf(this CodeWriter code, bool flag, string value = "") =>
- !flag ? code : code.AppendLine(value);
-
- public static CodeWriter AppendMultilineIf(this CodeWriter code, Func condition, string value = "") =>
- code.AppendMultilineIf(condition.Invoke(), value);
-
- public static CodeWriter AppendMultilineIf(this CodeWriter code, bool flag, string value = "") =>
- !flag ? code : code.AppendMultiline(value);
-
- public static CodeWriter AppendChildIf(this CodeWriter code, Func condition, Func childFunctions) =>
- code.AppendChildIf(condition.Invoke(), childFunctions);
-
- public static CodeWriter AppendChildIf(this CodeWriter code, bool flag, Func childFunctions) =>
- !flag ? code : childFunctions.Invoke();
-
- public static CodeWriter BeginBlockIf(this CodeWriter code, Func condition) =>
- code.BeginBlockIf(condition.Invoke());
-
- public static CodeWriter BeginBlockIf(this CodeWriter code, bool flag) =>
- !flag ? code : code.BeginBlock();
-
- public static CodeWriter EndBlockIf(this CodeWriter code, Func condition) =>
- code.EndBlockIf(condition.Invoke());
-
- public static CodeWriter EndBlockIf(this CodeWriter code, bool flag) =>
- !flag ? code : code.EndBlock();
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/FoundForGenerator.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/FoundForGenerator.cs
deleted file mode 100644
index 5a8bfa0..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/FoundForGenerator.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Aspid.Generator.Helpers;
-
-public readonly struct FoundForGenerator
-{
- public readonly bool IsNeed;
- public readonly T Container;
-
- public FoundForGenerator(T container)
- {
- IsNeed = true;
- Container = container;
- }
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/MembersByGroup.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/MembersByGroup.cs
similarity index 97%
rename from Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/MembersByGroup.cs
rename to Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/MembersByGroup.cs
index ffff928..f28c590 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Data/MembersByGroup.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/MembersByGroup.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
-namespace Aspid.Generator.Helpers;
+namespace Aspid.MVVM.Generators.Helpers;
public readonly struct MembersByGroup
{
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/NamespaceText.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/NamespaceText.cs
deleted file mode 100644
index b9f79a9..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/NamespaceText.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Aspid.Generator.Helpers;
-
-public sealed class NamespaceText(string name, NamespaceText? parent = null)
-{
- public string Name { get; } = (parent != null ? $"{parent}." : "") + name;
-
- public override string ToString() => Name;
-
- public static implicit operator string(NamespaceText @namespace) =>
- @namespace.ToString();
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/SymbolExtensions.cs
similarity index 55%
rename from Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.cs
rename to Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/SymbolExtensions.cs
index beabc6a..21ec8e4 100644
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/Extensions/Symbols/SymbolExtensions.cs
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/SymbolExtensions.cs
@@ -1,28 +1,9 @@
using Microsoft.CodeAnalysis;
-namespace Aspid.Generator.Helpers;
+namespace Aspid.MVVM.Generators.Helpers;
-public static partial class SymbolExtensions
+public static class SymbolExtensions
{
- public static string ToDisplayStringGlobal(this ISymbol symbol) =>
- symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
-
- public static ITypeSymbol? GetSymbolType(this ISymbol symbol) => symbol switch
- {
- ITypeSymbol type => type,
- IFieldSymbol field => field.Type,
- ILocalSymbol local => local.Type,
- IEventSymbol @event => @event.Type,
- IDiscardSymbol discard => discard.Type,
-
- // TODO Delete
- IMethodSymbol method => method.ReturnType,
-
- IPropertySymbol property => property.Type,
- IParameterSymbol parameter => parameter.Type,
- _ => null
- };
-
public static string GetFieldName(this ISymbol member, in string? prefix = "_") =>
GetFieldName(member.Name, prefix);
@@ -59,14 +40,17 @@ public static string RemoveFieldPrefix(this ISymbol member) =>
public static string RemoveFieldPrefix(in string name)
{
- var prefixCount = name.StartsWith("_")
+ var prefixCount = name.StartsWith("_")
? 1
- : name.StartsWith("m_") || name.StartsWith("s_")
- ? 2
+ : name.StartsWith("m_") || name.StartsWith("s_")
+ ? 2
: 0;
-
- return prefixCount > 0
- ? name.Remove(0, prefixCount)
+
+ return prefixCount > 0
+ ? name.Remove(0, prefixCount)
: name;
}
+
+ public static string CapitalizeFirstLetter(this string name) =>
+ name.Length == 0 ? name : char.ToUpper(name[0]) + name.Substring(1);
}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/TypeText.cs b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/TypeText.cs
deleted file mode 100644
index e4f0dfe..0000000
--- a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Helpers/TypeText.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Aspid.Generator.Helpers;
-
-public class TypeText(string name, NamespaceText? @namespace = null)
-{
- public string Name { get; } = name;
-
- public NamespaceText? Namespace { get; } = @namespace;
-
- public string FullName => (Namespace != null ? $"{Namespace}." : "") + Name;
-
- public string Global => $"global::{FullName}";
-
- public override string ToString() =>
- Global;
-
- public static implicit operator string(TypeText? type) =>
- type.ToString();
-}
\ No newline at end of file
diff --git a/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Properties/launchSettings.json b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Properties/launchSettings.json
new file mode 100644
index 0000000..dc7f06f
--- /dev/null
+++ b/Aspid.MVVM.Generators/Aspid.MVVM.Generators/Properties/launchSettings.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "DebugRoslynSourceGenerator": {
+ "commandName": "DebugRoslynComponent",
+ "targetProject": "../Aspid.MVVM.Generators.Sample/Aspid.MVVM.Generators.Sample.csproj"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 0000000..93f892a
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,11 @@
+
+
+
+
+ <_UnityDestination>$(MSBuildThisFileDirectory)../Aspid.MVVM/Assets/Aspid/MVVM/
+
+
+
+
+
+