Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"isRoot": true,
"tools": {
"dotnet-stryker": {
"version": "4.9.2",
"version": "4.11.0",
"commands": [
"dotnet-stryker"
],
"rollForward": false
},
"dotnet-reportgenerator-globaltool": {
"version": "5.4.11",
"version": "5.5.1",
"commands": [
"reportgenerator"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ protected override void ProcessClass(SourceProductionContext spc, INamedTypeSymb
"using System.CodeDom.Compiler;"
}.Concat(fields.Select(x => x!.NamespaceCode)).Distinct();

var mergeCode = $$"""
{{Helpers.CodeGeneratorAttribute}}
internal override bool TryMergeTo(SerializedCommand other) {
if (other is not {{className}} target) {
return false;
}

{{string.Join("\n", fields.Select(x => x!.MergeComparison))}}

{{string.Join("\n", fields.Select(x => x!.MergeCode))}}

return true;
}
""";

if (classSymbol.GetMembers().OfType<IMethodSymbol>().Any(x => x.Name == "TryMergeTo"))
{
mergeCode = string.Empty;
}

var fileContent = $$"""
{{string.Join("\n", namespaces)}}

Expand Down Expand Up @@ -88,6 +108,8 @@ public override byte[] Serialize(ProtocolVersion version) {

return buffer;
}

{{mergeCode}}
}

#nullable restore
Expand All @@ -105,18 +127,24 @@ public override byte[] Serialize(ProtocolVersion version) {
}

var propertyCode = GetPropertyCode(f);
var propertyName = Helpers.GetPropertyName(f);

return new SerializedField
{
SerializationCode = serializationCode,
PropertyCode = propertyCode,
NamespaceCode = Helpers.CreateNamespaceCode(f)
NamespaceCode = Helpers.CreateNamespaceCode(f),
MergeComparison = !HasProperty(f) ? $"if (target.{f.Name} != {f.Name}) {{ return false; }}" : string.Empty,
MergeCode = HasProperty(f) ? $"if (_{f.Name}_isDirty) {{ target.{propertyName} = {propertyName}; }}" : string.Empty,
};
}

private static bool HasProperty(IFieldSymbol f)
=> !f.GetAttributes().Any(a => a.AttributeClass?.Name == "NoPropertyAttribute");

private static string GetPropertyCode(IFieldSymbol f)
{
if (f.GetAttributes().Any(a => a.AttributeClass?.Name == "NoPropertyAttribute"))
if (!HasProperty(f))
{
return string.Empty;
}
Expand All @@ -130,17 +158,21 @@ private static string GetPropertyCode(IFieldSymbol f)
var docComment = Helpers.GetFieldMsDocComment(f);
var visibility = f.GetAttributes().Any(a => a.AttributeClass?.Name == "InternalPropertyAttribute") ? "internal" : "public";

var setter = f.IsReadOnly
var hasSetter = f.IsReadOnly || f.GetAttributes().Any(a => a.AttributeClass?.Name == "ReadOnlyAttribute");
var setter = hasSetter
? string.Empty
: $$"""
set {
{{validationCode}}
{{f.Name}} = value;
{{flagCode}}
_{{f.Name}}_isDirty = true;
}
""";

return $$"""
{{ ( hasSetter ? string.Empty : $"#pragma warning disable CS0414\nprivate bool _{f.Name}_isDirty;\n#pragma warning restore CS0414" ) }}

{{docComment}}
{{Helpers.CodeGeneratorAttribute}}
{{visibility}} {{fieldType}} {{propertyName}}
Expand Down
2 changes: 2 additions & 0 deletions AtemSharp.CodeGenerators/Serialization/SerializedField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ public class SerializedField
public string PropertyCode { get; set; } = string.Empty;
public string SerializationCode { get; set; } = string.Empty;
public string NamespaceCode { get; set; } = string.Empty;
public string MergeComparison { get; set; } = string.Empty;
public string MergeCode { get; set; } = string.Empty;
}
}
76 changes: 52 additions & 24 deletions AtemSharp.CodeGenerators/State/StateGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,50 @@ namespace AtemSharp.CodeGenerators.State;
public class StateGenerator : CodeGeneratorBase
{
private static readonly string[] HardCodedNamespaces =
{
"System.ComponentModel",
"System.Runtime.CompilerServices",
"System.CodeDom.Compiler"
};
{
"System.ComponentModel",
"System.Runtime.CompilerServices",
"System.CodeDom.Compiler"
};

protected override void ProcessClass(SourceProductionContext spc, INamedTypeSymbol classSymbol, ClassDeclarationSyntax classDecl)
{
var fields = classSymbol.GetMembers()
.OfType<IFieldSymbol>()
.Where(f => f.AssociatedSymbol is null)
.Where(f => !f.GetAttributes().Any(a => a.AttributeClass?.Name is "IgnoreDataMember" or "IgnoreDataMemberAttribute"))
.Where(f => !f.GetAttributes()
.Any(a => a.AttributeClass?.Name is "IgnoreDataMember" or "IgnoreDataMemberAttribute"))
.Where(f => !f.Name.Contains("<"))
.Select(ProcessField)
.ToArray();

var usings = HardCodedNamespaces.Concat(fields.Where(x => x.Namespace != string.Empty)
.Select(x => x.Namespace))
.Distinct()
.Select(x => $"using {x};")
.ToArray();
.Select(x => x.Namespace))
.Distinct()
.Select(x => $"using {x};")
.ToArray();

var propertyCopies = classSymbol.GetMembers().OfType<IPropertySymbol>()
.Where(x => x.Type.ContainingNamespace.ToString().Contains(".State"))
.Select(x => $"{x.Name}.CopyTo(target.{x.Name});")
.ToArray();

var internalCopy = classSymbol.GetMembers().OfType<IMethodSymbol>().Any(x => x.Name == "CopyToInternal")
? "CopyToInternal(target);"
: string.Empty;

var copyTo = $$"""
internal void CopyTo({{classSymbol.Name}} target) {
{{string.Join("\n", propertyCopies)}}
{{string.Join("\n", fields.Select(x => x.CopyCode))}}
{{internalCopy}}
}
""";

if (classSymbol.GetMembers().OfType<IMethodSymbol>().Any(x => x.Name == "CopyTo"))
{
copyTo = string.Empty;
}

spc.AddSource($"{classSymbol.Name}.g.cs", $$"""
#nullable enable
Expand All @@ -49,6 +72,9 @@ protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

{{copyTo}}

}
""");
}
Expand All @@ -73,28 +99,29 @@ private ProcessedField ProcessField(IFieldSymbol field)
var sendUpdateDeclaration = isReadOnly ? string.Empty : $"private partial void Send{propertyName}UpdateCommand({type} value);";

var code = $$"""
{{Helpers.CodeGeneratorAttribute}}
public {{type}} {{propertyName}} {
get => {{field.Name}};
{{setterCode}}
}
{{Helpers.CodeGeneratorAttribute}}
public {{type}} {{propertyName}} {
get => {{field.Name}};
{{setterCode}}
}

{{Helpers.CodeGeneratorAttribute}}
internal void Update{{propertyName}}({{type}} value) {
{{field.Name}} = value;
{{propertyName}}Changed?.Invoke(this, EventArgs.Empty);
OnPropertyChanged();
}
{{Helpers.CodeGeneratorAttribute}}
internal void Update{{propertyName}}({{type}} value) {
{{field.Name}} = value;
{{propertyName}}Changed?.Invoke(this, EventArgs.Empty);
OnPropertyChanged();
}

public event EventHandler? {{propertyName}}Changed;
public event EventHandler? {{propertyName}}Changed;

{{sendUpdateDeclaration}}
""";
{{sendUpdateDeclaration}}
""";

return new ProcessedField
{
FieldCode = code,
Namespace = field.Type.ContainingNamespace.ToString() ?? string.Empty,
CopyCode = $"target.Update{propertyName}({propertyName});"
};
}

Expand All @@ -108,5 +135,6 @@ public class ProcessedField
{
public string FieldCode { get; set; } = string.Empty;
public string Namespace { get; set; } = string.Empty;
public string CopyCode { get; set; } = string.Empty;
}
}
3 changes: 2 additions & 1 deletion AtemSharp.Tests/AtemSharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit" Version="4.4.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.4.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
<PackageReference Include="Verify.NUnit" Version="31.9.3" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading