@@ -186,7 +186,108 @@ public void GenericListClass_Should_Use_FastCloner_For_Items()
186186 Assert . That ( clone . Items [ 0 ] , Is . Not . SameAs ( original . Items [ 0 ] ) ) ; // Should be deep cloned
187187 }
188188
189- // Helper method to run the generator
189+ [ Test ]
190+ public void GeneratedCode_ForCollectionWithNonClonableElements_ShouldNotProduceNullableWarnings ( )
191+ {
192+ string source = @"
193+ #nullable enable
194+ using FastCloner.SourceGenerator.Shared;
195+ using System.Collections.Generic;
196+
197+ namespace TestNamespace;
198+
199+ public class NonClonableItem
200+ {
201+ public NonClonableItem(int x) { Value = x; }
202+ public int Value { get; set; }
203+ }
204+
205+ [FastClonerClonable]
206+ public class ClassWithNonClonableCollection
207+ {
208+ public List<NonClonableItem> Items { get; set; } = new();
209+ }
210+ " ;
211+ ( ImmutableArray < Diagnostic > _ , ImmutableArray < Diagnostic > compilationDiags ) = RunGeneratorAndCompile ( source ) ;
212+
213+ List < Diagnostic > nullableWarnings = compilationDiags
214+ . Where ( d => d . Id is "CS8604" or "CS8600" )
215+ . Where ( d => d . Severity == DiagnosticSeverity . Warning )
216+ . ToList ( ) ;
217+
218+ Assert . That ( nullableWarnings , Is . Empty ,
219+ "Generated code should not produce nullable warnings (CS8604/CS8600). " +
220+ $ "Found: { string . Join ( "; " , nullableWarnings . Select ( d => $ "{ d . Id } : { d . GetMessage ( ) } ") ) } ") ;
221+ }
222+
223+ [ Test ]
224+ public void GeneratedCode_ForArrayWithNonClonableElements_ShouldNotProduceNullableWarnings ( )
225+ {
226+ string source = @"
227+ #nullable enable
228+ using FastCloner.SourceGenerator.Shared;
229+
230+ namespace TestNamespace;
231+
232+ public class NonClonableItem
233+ {
234+ public NonClonableItem(int x) { Value = x; }
235+ public int Value { get; set; }
236+ }
237+
238+ [FastClonerClonable]
239+ public class ClassWithNonClonableArray
240+ {
241+ public NonClonableItem[] Items { get; set; } = [];
242+ }
243+ " ;
244+ ( ImmutableArray < Diagnostic > _ , ImmutableArray < Diagnostic > compilationDiags ) = RunGeneratorAndCompile ( source ) ;
245+
246+ List < Diagnostic > nullableWarnings = compilationDiags
247+ . Where ( d => d . Id is "CS8604" or "CS8600" )
248+ . Where ( d => d . Severity == DiagnosticSeverity . Warning )
249+ . ToList ( ) ;
250+
251+ Assert . That ( nullableWarnings , Is . Empty ,
252+ "Generated code should not produce nullable warnings for arrays. " +
253+ $ "Found: { string . Join ( "; " , nullableWarnings . Select ( d => $ "{ d . Id } : { d . GetMessage ( ) } ") ) } ") ;
254+ }
255+
256+ [ Test ]
257+ public void GeneratedCode_ForDictionaryWithNonClonableValues_ShouldNotProduceNullableWarnings ( )
258+ {
259+ string source = @"
260+ #nullable enable
261+ using FastCloner.SourceGenerator.Shared;
262+ using System.Collections.Generic;
263+
264+ namespace TestNamespace;
265+
266+ public class NonClonableItem
267+ {
268+ public NonClonableItem(int x) { Value = x; }
269+ public int Value { get; set; }
270+ }
271+
272+ [FastClonerClonable]
273+ public class ClassWithNonClonableDictionary
274+ {
275+ public Dictionary<string, NonClonableItem> Items { get; set; } = new();
276+ }
277+ " ;
278+ ( ImmutableArray < Diagnostic > _ , ImmutableArray < Diagnostic > compilationDiags ) = RunGeneratorAndCompile ( source ) ;
279+
280+ List < Diagnostic > nullableWarnings = compilationDiags
281+ . Where ( d => d . Id is "CS8604" or "CS8600" )
282+ . Where ( d => d . Severity == DiagnosticSeverity . Warning )
283+ . ToList ( ) ;
284+
285+ Assert . That ( nullableWarnings , Is . Empty ,
286+ "Generated code should not produce nullable warnings for dictionaries. " +
287+ $ "Found: { string . Join ( "; " , nullableWarnings . Select ( d => $ "{ d . Id } : { d . GetMessage ( ) } ") ) } ") ;
288+ }
289+
290+ // Helper method to run the generator (returns only generator diagnostics)
190291 private static ImmutableArray < Diagnostic > RunGenerator ( string source )
191292 {
192293 SyntaxTree syntaxTree = CSharpSyntaxTree . ParseText ( source ) ;
@@ -214,6 +315,40 @@ private static ImmutableArray<Diagnostic> RunGenerator(string source)
214315 return result . Diagnostics ;
215316 }
216317
318+ /// <summary>
319+ /// Runs the generator and compiles the result, returning both generator and compilation diagnostics.
320+ /// Includes FastCloner runtime reference so DeepClone fallback code is generated.
321+ /// </summary>
322+ private static ( ImmutableArray < Diagnostic > GeneratorDiags , ImmutableArray < Diagnostic > CompilationDiags ) RunGeneratorAndCompile ( string source )
323+ {
324+ SyntaxTree syntaxTree = CSharpSyntaxTree . ParseText ( source ) ;
325+
326+ List < MetadataReference > references =
327+ [
328+ MetadataReference . CreateFromFile ( typeof ( object ) . Assembly . Location ) ,
329+ MetadataReference . CreateFromFile ( typeof ( FastClonerClonableAttribute ) . Assembly . Location ) ,
330+ MetadataReference . CreateFromFile ( typeof ( FastCloner ) . Assembly . Location ) ,
331+ MetadataReference . CreateFromFile ( Assembly . Load ( "System.Runtime" ) . Location ) ,
332+ MetadataReference . CreateFromFile ( Assembly . Load ( "System.Collections" ) . Location ) ,
333+ MetadataReference . CreateFromFile ( Assembly . Load ( "netstandard" ) . Location )
334+ ] ;
335+
336+ CSharpCompilation compilation = CSharpCompilation . Create (
337+ "TestAssembly" ,
338+ [ syntaxTree ] ,
339+ references ,
340+ new CSharpCompilationOptions ( OutputKind . DynamicallyLinkedLibrary ,
341+ nullableContextOptions : NullableContextOptions . Enable ) ) ;
342+
343+ FastClonerIncrementalGenerator generator = new FastClonerIncrementalGenerator ( ) ;
344+ GeneratorDriver driver = CSharpGeneratorDriver . Create ( generator ) ;
345+
346+ driver . RunGeneratorsAndUpdateCompilation ( compilation , out Compilation outputCompilation , out ImmutableArray < Diagnostic > generatorDiags ) ;
347+
348+ ImmutableArray < Diagnostic > compilationDiags = outputCompilation . GetDiagnostics ( ) ;
349+ return ( generatorDiags , compilationDiags ) ;
350+ }
351+
217352 public class UnclonableClass
218353 {
219354 public int Value { get ; set ; }
0 commit comments