Skip to content

Commit

Permalink
fix: correctly annotate nullable generics in disabled nullable contex…
Browse files Browse the repository at this point in the history
…ts (#1020)
  • Loading branch information
latonz committed Dec 18, 2023
1 parent 567c8b3 commit d35c52d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/Riok.Mapperly/Helpers/NullableSymbolExtensions.cs
@@ -1,3 +1,4 @@
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;

Expand Down Expand Up @@ -38,7 +39,7 @@ internal static bool TryUpgradeNullable(this ITypeSymbol symbol, [NotNullWhen(tr
return false;
}

upgradedSymbol = symbol.WithNullableAnnotation(NullableAnnotation.Annotated);
upgradedSymbol = symbol.WithDeepNullableAnnotation(NullableAnnotation.Annotated);
return true;
}

Expand Down Expand Up @@ -112,4 +113,24 @@ internal static bool IsNullable(this ITypeParameterSymbol typeParameter, Nullabl

internal static bool IsNullable(this NullableAnnotation nullable) =>
nullable is NullableAnnotation.Annotated or NullableAnnotation.None;

/// <summary>
/// Returns a new type symbol with the provided nullable annotation.
/// Also sets the nullable annotation on all type arguments of the <see cref="symbol"/>.
/// </summary>
/// <param name="symbol">The symbol to work on.</param>
/// <param name="annotation">The <see cref="NullableAnnotation"/> to set.</param>
/// <returns>The new symbol with the given nullable annotation.</returns>
private static ITypeSymbol WithDeepNullableAnnotation(this ITypeSymbol symbol, NullableAnnotation annotation)
{
if (symbol is INamedTypeSymbol { TypeArguments.Length: > 0 } namedSymbol)
{
symbol = namedSymbol.ConstructedFrom.Construct(
namedSymbol.TypeArguments,
Enumerable.Repeat(annotation, namedSymbol.TypeArguments.Length).ToImmutableArray()
);
}

return symbol.WithNullableAnnotation(annotation);
}
}
8 changes: 8 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/EnumerableTest.cs
Expand Up @@ -550,6 +550,14 @@ public Task ArrayToReadOnlyCollectionShouldUpgradeNullability()
return TestHelper.VerifyGenerator(source, TestHelperOptions.DisabledNullable);
}

[Fact]
public Task ShouldUpgradeNullabilityOfGenericInDisabledNullableContext()
{
var source = TestSourceBuilder.Mapping("IList<A>", "IList<B>", "record A(int V);", "record B(int V);");

return TestHelper.VerifyGenerator(source, TestHelperOptions.DisabledNullable);
}

[Fact]
public Task ArrayToCollectionShouldUpgradeNullability()
{
Expand Down
@@ -0,0 +1,25 @@
//HintName: Mapper.g.cs
// <auto-generated />
#nullable enable
public partial class Mapper
{
private partial global::System.Collections.Generic.IList<global::B?>? Map(global::System.Collections.Generic.IList<global::A?>? source)
{
if (source == null)
return default;
var target = new global::System.Collections.Generic.List<global::B?>(source.Count);
foreach (var item in source)
{
target.Add(MapToB(item));
}
return target;
}

private global::B? MapToB(global::A? source)
{
if (source == null)
return default;
var target = new global::B(source.V);
return target;
}
}

0 comments on commit d35c52d

Please sign in to comment.