Skip to content

Commit

Permalink
WIP: Add AggressiveInliningMode and implement the functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
mjebrahimi committed Aug 19, 2024
1 parent 05ab18c commit 40654d2
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 2 deletions.
27 changes: 27 additions & 0 deletions src/Riok.Mapperly.Abstractions/AggressiveInliningMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Riok.Mapperly.Abstractions;

/// <summary>
/// Indicates how AggressiveInlining should be applied to methods.
/// </summary>
public enum AggressiveInliningMode
{
/// <summary>
/// Does not apply AggressiveInlining
/// </summary>
None,

/// <summary>
/// Applies AggressiveInlining to value types
/// </summary>
ValueTypes,

/// <summary>
/// Applies AggressiveInlining to reference types
/// </summary>
ReferenceTypes,

/// <summary>
/// Applies AggressiveInlining to all types
/// </summary>
All,
}
6 changes: 6 additions & 0 deletions src/Riok.Mapperly.Abstractions/MapperAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,10 @@ public class MapperAttribute : Attribute
/// partial methods are discovered.
/// </summary>
public bool AutoUserMappings { get; set; } = true;

/// <summary>
/// Gets or sets the aggressive inlining mode.
/// Defaults to <see cref="AggressiveInliningMode.ValueTypes"/>.
/// </summary>
public AggressiveInliningMode AggressiveInliningMode { get; set; } = AggressiveInliningMode.ValueTypes;
}
7 changes: 7 additions & 0 deletions src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,10 @@ Riok.Mapperly.Abstractions.MappingTargetAttribute
Riok.Mapperly.Abstractions.MappingTargetAttribute.MappingTargetAttribute() -> void
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string! source, string![]! target) -> void
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string![]! source, string! target) -> void
Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.AggressiveInliningMode.None = 0 -> Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.AggressiveInliningMode.ValueTypes = 1 -> Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.AggressiveInliningMode.ReferenceTypes = 2 -> Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.AggressiveInliningMode.All = 3 -> Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.MapperAttribute.AggressiveInliningMode.get -> Riok.Mapperly.Abstractions.AggressiveInliningMode
Riok.Mapperly.Abstractions.MapperAttribute.AggressiveInliningMode.set -> void
6 changes: 6 additions & 0 deletions src/Riok.Mapperly/Configuration/MapperConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,10 @@ public record MapperConfiguration
/// Whether to consider non-partial methods in a mapper as user implemented mapping methods.
/// </summary>
public bool? AutoUserMappings { get; init; }

/// <summary>
/// Gets or sets the aggressive inlining mode.
/// Defaults to <see cref="AggressiveInliningMode.ValueTypes"/>.
/// </summary>
public AggressiveInliningMode? AggressiveInliningMode { get; set; }
}
5 changes: 5 additions & 0 deletions src/Riok.Mapperly/Configuration/MapperConfigurationMerger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public static MapperAttribute Merge(MapperConfiguration mapperConfiguration, Map
mapper.AutoUserMappings =
mapperConfiguration.AutoUserMappings ?? defaultMapperConfiguration.AutoUserMappings ?? mapper.AutoUserMappings;

mapper.AggressiveInliningMode =
mapperConfiguration.AggressiveInliningMode
?? defaultMapperConfiguration.AggressiveInliningMode
?? mapper.AggressiveInliningMode;

return mapper;
}
}
31 changes: 30 additions & 1 deletion src/Riok.Mapperly/Descriptors/Mappings/MethodMapping.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Riok.Mapperly.Abstractions;
using Riok.Mapperly.Emit;
using Riok.Mapperly.Emit.Syntax;
using Riok.Mapperly.Helpers;
Expand Down Expand Up @@ -96,10 +98,37 @@ public virtual MethodDeclarationSyntax BuildMethod(SourceEmitterContext ctx)
return MethodDeclaration(returnType.AddTrailingSpace(), Identifier(MethodName))
.WithModifiers(TokenList(BuildModifiers(ctx.IsStatic)))
.WithParameterList(parameters)
.WithAttributeLists(ctx.SyntaxFactory.GeneratedCodeAttributeList())
.WithAttributeLists(ctx.SyntaxFactory.GeneratedCodeAttributeList().AddRange(GenerateMethodImplAttributeListIfNeeded(ctx)))
.WithBody(ctx.SyntaxFactory.Block(BuildBody(typeMappingBuildContext)));
}

private SyntaxList<AttributeListSyntax> GenerateMethodImplAttributeListIfNeeded(SourceEmitterContext ctx)
{
var hasMethodImplAttribute = MethodDeclarationSyntax.HasAttribute<MethodImplAttribute>();

//Skip if method already has [MethodImple] attribute
if (hasMethodImplAttribute)
return [];

var aggressiveInliningMode = GetAggressiveInliningMode();

return aggressiveInliningMode switch
{
AggressiveInliningMode.ValueTypes when SourceType.IsValueType => ctx.SyntaxFactory.MethodImplAttributeList(),
AggressiveInliningMode.ReferenceTypes when SourceType.IsReferenceType => ctx.SyntaxFactory.MethodImplAttributeList(),
AggressiveInliningMode.All => ctx.SyntaxFactory.MethodImplAttributeList(),
AggressiveInliningMode.None => [],
_ => [],
};
}

private AggressiveInliningMode GetAggressiveInliningMode()
{
//Read value from AggressiveInliningMode property of [Mapper] attribute annotated on containing class
//I guess from SimpleMappingBuilderContext.Configuration.Mapper.AggressiveInliningMode
return AggressiveInliningMode.ReferenceTypes;
}

public abstract IEnumerable<StatementSyntax> BuildBody(TypeMappingBuildContext ctx);

internal void SetMethodNameIfNeeded(Func<MethodMapping, string> methodNameBuilder)
Expand Down
7 changes: 7 additions & 0 deletions src/Riok.Mapperly/Emit/Syntax/SyntaxFactoryHelper.Literal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@ public static LiteralExpressionSyntax BooleanLiteral(bool b) =>

public static LiteralExpressionSyntax StringLiteral(string content) =>
LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(content));

public static MemberAccessExpressionSyntax EnumLiteral(Enum @enum) =>
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName($"global::{@enum.GetType().FullName}"),
IdentifierName(@enum.ToString())
);
}
15 changes: 15 additions & 0 deletions src/Riok.Mapperly/Emit/Syntax/SyntaxFactoryHelper.MethodImpl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Riok.Mapperly.Emit.Syntax;

public partial struct SyntaxFactoryHelper
{
private const string MethodImplAttributeName = "global::System.Runtime.CompilerServices.MethodImpl";

public SyntaxList<AttributeListSyntax> MethodImplAttributeList()
{
return AttributeList(MethodImplAttributeName, EnumLiteral(MethodImplOptions.AggressiveInlining));
}
}
28 changes: 28 additions & 0 deletions src/Riok.Mapperly/Helpers/MethodDeclarationSyntaxExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Riok.Mapperly.Helpers;

public static class MethodDeclarationSyntaxExtensions
{
public static bool HasAttribute<TAttribute>(this MethodDeclarationSyntax methodDeclarationSyntax)
where TAttribute : Attribute
{
var csharpCompilation = CSharpCompilation.Create(
assemblyName: null,
syntaxTrees: [methodDeclarationSyntax!.SyntaxTree],
references: [MetadataReference.CreateFromFile(typeof(TAttribute).Assembly.Location)]
);

var semanticModel = csharpCompilation.GetSemanticModel(methodDeclarationSyntax.SyntaxTree);

var attributes = methodDeclarationSyntax.AttributeLists.SelectMany(p => p.Attributes);

return attributes.Any(attributeSyntax =>
{
var symbols = semanticModel.GetSymbolInfo(attributeSyntax).CandidateSymbols.OfType<IMethodSymbol>();
return symbols.Any(p => string.Equals(p.ContainingType.ToString(), typeof(TAttribute).FullName, StringComparison.Ordinal));
});
}
}
1 change: 1 addition & 0 deletions test/Riok.Mapperly.Tests/TestSourceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private static string BuildAttribute(TestSourceBuilderOptions options)
Attribute(options.IncludedMembers),
Attribute(options.PreferParameterlessConstructors),
Attribute(options.AutoUserMappings),
Attribute(options.AggressiveInliningMode),
}.WhereNotNull();

return $"[Mapper({string.Join(", ", attrs)})]";
Expand Down
6 changes: 5 additions & 1 deletion test/Riok.Mapperly.Tests/TestSourceBuilderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public record TestSourceBuilderOptions(
MemberVisibility? IncludedMembers = null,
bool Static = false,
bool PreferParameterlessConstructors = true,
bool AutoUserMappings = true
bool AutoUserMappings = true,
AggressiveInliningMode? AggressiveInliningMode = null
)
{
public const string DefaultMapperClassName = "Mapper";
Expand All @@ -44,6 +45,9 @@ public static TestSourceBuilderOptions WithRequiredMappingStrategy(RequiredMappi
public static TestSourceBuilderOptions WithMemberVisibility(MemberVisibility memberVisibility) =>
new(IncludedMembers: memberVisibility);

public static TestSourceBuilderOptions WithAggressiveInliningMode(AggressiveInliningMode aggressiveInliningMode) =>
new(AggressiveInliningMode: aggressiveInliningMode);

public static TestSourceBuilderOptions WithDisabledMappingConversion(params MappingConversionType[] conversionTypes)
{
var enabled = MappingConversionType.All;
Expand Down

0 comments on commit 40654d2

Please sign in to comment.