From 621ecb38034dd24175be840c03d2726ca26e8f10 Mon Sep 17 00:00:00 2001 From: Andreas Ravnestad Date: Thu, 20 Aug 2026 10:37:26 +0200 Subject: [PATCH] fix: Handle mapper interface generation for internal types --- .../ExpressionTranslator.cs | 18 ++++++---- .../Mappers/IIssue399Mapper.cs | 10 ++++++ .../Mappers/Issue399Mapper.cs | 24 +++++++++++++ .../WhenMapperInterfaceUsesInternalTypes.cs | 34 +++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/Mapster.Tool.Tests/Mappers/IIssue399Mapper.cs create mode 100644 src/Mapster.Tool.Tests/Mappers/Issue399Mapper.cs create mode 100644 src/Mapster.Tool.Tests/WhenMapperInterfaceUsesInternalTypes.cs diff --git a/src/ExpressionTranslator/ExpressionTranslator.cs b/src/ExpressionTranslator/ExpressionTranslator.cs index 6c219f86..7a1e3e36 100644 --- a/src/ExpressionTranslator/ExpressionTranslator.cs +++ b/src/ExpressionTranslator/ExpressionTranslator.cs @@ -56,6 +56,15 @@ private void ResetIndentLevel() _indentLevel++; } + private bool IsGeneratedTypeInternal() + { + if (Definitions == null) + return false; + + return Definitions.IsInternal || + Definitions.Implements?.Any(it => !it.GetTypeInfo().IsVisible) == true; + } + public static ExpressionTranslator Create(Expression node, ExpressionDefinitions? definitions = null) { var translator = new ExpressionTranslator(definitions); @@ -1201,7 +1210,7 @@ public Expression VisitLambda(LambdaExpression node, LambdaType type, string? me if (type == LambdaType.PublicLambda) { var name = methodName ?? "Main"; - if (!isInternal) + if (!isInternal && !IsGeneratedTypeInternal()) isInternal = node.ReturnType.GetTypeInfo().IsNotPublic || node.Parameters.Any(it => it.Type.GetTypeInfo().IsNotPublic); WriteModifierNextLine(isInternal ? "internal" : "public"); @@ -1235,7 +1244,7 @@ public Expression VisitLambda(LambdaExpression node, LambdaType type, string? me var name = methodName ?? "Main"; if (type == LambdaType.PublicMethod || type == LambdaType.ExtensionMethod) { - if (!isInternal) + if (!isInternal && !IsGeneratedTypeInternal()) isInternal = node.ReturnType.GetTypeInfo().IsNotPublic || node.Parameters.Any(it => it.Type.GetTypeInfo().IsNotPublic); WriteModifierNextLine(isInternal ? "internal" : "public"); @@ -1891,10 +1900,7 @@ public override string ToString() Indent(); } - var isInternal = Definitions.IsInternal; - if (!isInternal) - isInternal = Definitions.Implements?.Any(it => - !it.GetTypeInfo().IsInterface && !it.GetTypeInfo().IsPublic) ?? false; + var isInternal = IsGeneratedTypeInternal(); WriteModifierNextLine(isInternal ? "internal" : "public"); Write("partial ", Definitions.IsRecordType ? "record " : "class ", Definitions.TypeName); if (Definitions.IsRecordType && ctorParams?.Count > 0) diff --git a/src/Mapster.Tool.Tests/Mappers/IIssue399Mapper.cs b/src/Mapster.Tool.Tests/Mappers/IIssue399Mapper.cs new file mode 100644 index 00000000..9d4dee1c --- /dev/null +++ b/src/Mapster.Tool.Tests/Mappers/IIssue399Mapper.cs @@ -0,0 +1,10 @@ +using System.Linq.Expressions; + +namespace Mapster.Tool.Tests.Mappers; + +[Mapper] +internal interface IIssue399Mapper +{ + Expression> ProjectToDestination { get; } + Issue399Destination Map(Issue399Source source); +} diff --git a/src/Mapster.Tool.Tests/Mappers/Issue399Mapper.cs b/src/Mapster.Tool.Tests/Mappers/Issue399Mapper.cs new file mode 100644 index 00000000..bdcd5a94 --- /dev/null +++ b/src/Mapster.Tool.Tests/Mappers/Issue399Mapper.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq.Expressions; +using Mapster.Tool.Tests; +using Mapster.Tool.Tests.Mappers; + +namespace Mapster.Tool.Tests.Mappers +{ + internal partial class Issue399Mapper : IIssue399Mapper + { + public Expression> ProjectToDestination => p1 => new Issue399Destination() + { + Id = p1.Id, + Name = p1.Name + }; + public Issue399Destination Map(Issue399Source p2) + { + return p2 == null ? null : new Issue399Destination() + { + Id = p2.Id, + Name = p2.Name + }; + } + } +} \ No newline at end of file diff --git a/src/Mapster.Tool.Tests/WhenMapperInterfaceUsesInternalTypes.cs b/src/Mapster.Tool.Tests/WhenMapperInterfaceUsesInternalTypes.cs new file mode 100644 index 00000000..00b09672 --- /dev/null +++ b/src/Mapster.Tool.Tests/WhenMapperInterfaceUsesInternalTypes.cs @@ -0,0 +1,34 @@ +using FluentAssertions; +using Mapster.Tool.Tests.Mappers; + +namespace Mapster.Tool.Tests; + +/// +/// Tests for https://github.com/MapsterMapper/Mapster/issues/399 +/// +public class WhenMapperInterfaceUsesInternalTypes : TestBase +{ + [Fact] + public void MapperInterfaceImplementationUsesInternalTypes() + { + IIssue399Mapper mapper = new Issue399Mapper(); + var source = new Issue399Source { Id = 1, Name = "Test" }; + + var destination = mapper.Map(source); + + destination.Id.Should().Be(source.Id); + destination.Name.Should().Be(source.Name); + } +} + +internal class Issue399Source +{ + public int Id { get; init; } + public string? Name { get; init; } +} + +internal class Issue399Destination +{ + public int Id { get; init; } + public string? Name { get; init; } +}