diff --git a/SpreadCheetah.SourceGenerator.SnapshotTest/Snapshots/G.CellValueConverter_ClassWithConverterOnComplexProperty#MyNamespace.MyGenRowContext.g.verified.cs b/SpreadCheetah.SourceGenerator.SnapshotTest/Snapshots/G.CellValueConverter_ClassWithConverterOnComplexProperty#MyNamespace.MyGenRowContext.g.verified.cs
new file mode 100644
index 0000000..42c928b
--- /dev/null
+++ b/SpreadCheetah.SourceGenerator.SnapshotTest/Snapshots/G.CellValueConverter_ClassWithConverterOnComplexProperty#MyNamespace.MyGenRowContext.g.verified.cs
@@ -0,0 +1,135 @@
+//HintName: MyNamespace.MyGenRowContext.g.cs
+//
+#nullable enable
+using SpreadCheetah;
+using SpreadCheetah.SourceGeneration;
+using SpreadCheetah.Styling;
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MyNamespace
+{
+ public partial class MyGenRowContext
+ {
+ private static MyGenRowContext? _default;
+ public static MyGenRowContext Default => _default ??= new MyGenRowContext();
+
+ public MyGenRowContext()
+ {
+ }
+ private static readonly MyNamespace.ObjectConverter _valueConverter0 = new MyNamespace.ObjectConverter();
+ private static readonly MyNamespace.StringConverter _valueConverter1 = new MyNamespace.StringConverter();
+
+ private WorksheetRowTypeInfo? _ClassWithoutParameterlessConstructor;
+ public WorksheetRowTypeInfo ClassWithoutParameterlessConstructor => _ClassWithoutParameterlessConstructor
+ ??= WorksheetRowMetadataServices.CreateObjectInfo(
+ AddHeaderRow0Async, AddAsRowAsync, AddRangeAsRowsAsync, null, CreateWorksheetRowDependencyInfo0);
+
+ private static WorksheetRowDependencyInfo CreateWorksheetRowDependencyInfo0(Spreadsheet spreadsheet)
+ {
+ var styleIds = new[]
+ {
+ spreadsheet.GetStyleId("object style"),
+ };
+ return new WorksheetRowDependencyInfo(styleIds);
+ }
+
+ private static async ValueTask AddHeaderRow0Async(SpreadCheetah.Spreadsheet spreadsheet, SpreadCheetah.Styling.StyleId? styleId, CancellationToken token)
+ {
+ var cells = ArrayPool.Shared.Rent(4);
+ try
+ {
+ cells[0] = new StyledCell("Value", styleId);
+ cells[1] = new StyledCell("Value1", styleId);
+ cells[2] = new StyledCell("StringProp", styleId);
+ cells[3] = new StyledCell("StringProp1", styleId);
+ await spreadsheet.AddRowAsync(cells.AsMemory(0, 4), token).ConfigureAwait(false);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(cells, true);
+ }
+ }
+
+ private static ValueTask AddAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet, MyNamespace.ClassWithoutParameterlessConstructor? obj, CancellationToken token)
+ {
+ if (spreadsheet is null)
+ throw new ArgumentNullException(nameof(spreadsheet));
+ if (obj is null)
+ return spreadsheet.AddRowAsync(ReadOnlyMemory.Empty, token);
+ return AddAsRowInternalAsync(spreadsheet, obj, token);
+ }
+
+ private static ValueTask AddRangeAsRowsAsync(SpreadCheetah.Spreadsheet spreadsheet,
+ IEnumerable objs,
+ CancellationToken token)
+ {
+ if (spreadsheet is null)
+ throw new ArgumentNullException(nameof(spreadsheet));
+ if (objs is null)
+ throw new ArgumentNullException(nameof(objs));
+ return AddRangeAsRowsInternalAsync(spreadsheet, objs, token);
+ }
+
+ private static async ValueTask AddAsRowInternalAsync(SpreadCheetah.Spreadsheet spreadsheet,
+ MyNamespace.ClassWithoutParameterlessConstructor obj,
+ CancellationToken token)
+ {
+ var cells = ArrayPool.Shared.Rent(4);
+ try
+ {
+ var worksheetRowDependencyInfo = spreadsheet.GetOrCreateWorksheetRowDependencyInfo(Default.ClassWithoutParameterlessConstructor);
+ var styleIds = worksheetRowDependencyInfo.StyleIds;
+ await AddCellsAsRowAsync(spreadsheet, obj, cells, styleIds, token).ConfigureAwait(false);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(cells, true);
+ }
+ }
+
+ private static async ValueTask AddRangeAsRowsInternalAsync(SpreadCheetah.Spreadsheet spreadsheet,
+ IEnumerable objs,
+ CancellationToken token)
+ {
+ var cells = ArrayPool.Shared.Rent(4);
+ try
+ {
+ var worksheetRowDependencyInfo = spreadsheet.GetOrCreateWorksheetRowDependencyInfo(Default.ClassWithoutParameterlessConstructor);
+ var styleIds = worksheetRowDependencyInfo.StyleIds;
+ foreach (var obj in objs)
+ {
+ await AddCellsAsRowAsync(spreadsheet, obj, cells, styleIds, token).ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(cells, true);
+ }
+ }
+
+ private static ValueTask AddCellsAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet,
+ MyNamespace.ClassWithoutParameterlessConstructor? obj,
+ StyledCell[] cells, IReadOnlyList styleIds, CancellationToken token)
+ {
+ if (obj is null)
+ return spreadsheet.AddRowAsync(ReadOnlyMemory.Empty, token);
+
+ cells[0] = new StyledCell(_valueConverter0.ConvertToDataCell(obj.Value), null);
+ cells[1] = new StyledCell(_valueConverter0.ConvertToDataCell(obj.Value1), styleIds[0]);
+ cells[2] = new StyledCell(new DataCell(obj.StringProp), null);
+ cells[3] = new StyledCell(_valueConverter1.ConvertToDataCell(obj.StringProp1), null);
+ return spreadsheet.AddRowAsync(cells.AsMemory(0, 4), token);
+ }
+
+ private static DataCell ConstructTruncatedDataCell(string? value, int truncateLength)
+ {
+ return value is null || value.Length <= truncateLength
+ ? new DataCell(value)
+ : new DataCell(value.AsMemory(0, truncateLength));
+ }
+ }
+}
diff --git a/SpreadCheetah.SourceGenerator.SnapshotTest/Tests/CellValueConverterTests.cs b/SpreadCheetah.SourceGenerator.SnapshotTest/Tests/CellValueConverterTests.cs
index def593e..223ee72 100644
--- a/SpreadCheetah.SourceGenerator.SnapshotTest/Tests/CellValueConverterTests.cs
+++ b/SpreadCheetah.SourceGenerator.SnapshotTest/Tests/CellValueConverterTests.cs
@@ -256,4 +256,45 @@ public partial class MyGenRowContext : WorksheetRowContext;
// Act & Assert
return TestHelper.CompileAndVerify(source, onlyDiagnostics: true);
}
+
+ [Fact]
+ public Task CellValueConverter_ClassWithConverterOnComplexProperty()
+ {
+ // Arrange
+ const string source = """
+ using SpreadCheetah.SourceGeneration;
+
+ namespace MyNamespace;
+ public class ClassWithoutParameterlessConstructor
+ {
+ [CellValueConverter(typeof(ObjectConverter))]
+ public object? Value { get; set; }
+
+ [CellValueConverter(typeof(ObjectConverter))]
+ [CellStyle("object style")]
+ public object? Value1 { get; set; }
+
+ public string StringProp { get; set; }
+
+ [CellValueConverter(typeof(StringConverter))]
+ public string StringProp1 { get; set; }
+ }
+
+ internal class ObjectConverter : CellValueConverter