From 8443d3dd7ccc60643f4e854019716180541a6257 Mon Sep 17 00:00:00 2001 From: Timothy Makkison Date: Sat, 8 Jul 2023 11:01:06 +0100 Subject: [PATCH] chore: remove linq func allocations, add `IsRefLikeType` and `NullableValue` check --- .../Enumerables/CollectionInfoBuilder.cs | 23 +++++++++++++------ .../Descriptors/SymbolAccessor.cs | 17 +++++++++++--- .../Helpers/NullableSymbolExtensions.cs | 7 +----- src/Riok.Mapperly/Helpers/SymbolExtensions.cs | 15 ++++++++---- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/Riok.Mapperly/Descriptors/Enumerables/CollectionInfoBuilder.cs b/src/Riok.Mapperly/Descriptors/Enumerables/CollectionInfoBuilder.cs index 082bdc93ee..14b2dcffcf 100644 --- a/src/Riok.Mapperly/Descriptors/Enumerables/CollectionInfoBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/Enumerables/CollectionInfoBuilder.cs @@ -100,7 +100,7 @@ ITypeSymbol enumeratedType typeInfo, GetImplementedCollectionTypes(wellKnownTypes, type, typeInfo), enumeratedType, - FindCountProperty(wellKnownTypes, symbolAccessor, type, typeInfo), + FindCountProperty(symbolAccessor, type, typeInfo), HasValidAddMethod(wellKnownTypes, type, typeInfo), collectionTypeInfo?.Immutable == true ); @@ -115,11 +115,20 @@ ITypeSymbol enumeratedType if (type is not ({ IsValueType: true, IsReadOnly: true } and INamedTypeSymbol { TypeArguments.Length: 1 } namedType)) return null; - // if the collection is Span<> or Memory<> etc, get the type symbol + // if the collection is a ref type the check for Span<> or ReadOnlySpanSpan<> if ( - SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(Span<>))) - || SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(ReadOnlySpan<>))) - || SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(Memory<>))) + namedType.IsRefLikeType + && ( + SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(Span<>))) + || SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(ReadOnlySpan<>))) + ) + ) + { + return namedType.TypeArguments[0]; + } + // Memory<> or ReadOnlyMemory<> etc, get the type symbol + if ( + SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(Memory<>))) || SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, types.Get(typeof(ReadOnlyMemory<>))) ) { @@ -149,7 +158,7 @@ or CollectionType.SortedSet || t.HasImplicitGenericImplementation(types.Get(typeof(ISet<>)), nameof(ISet.Add)); } - private static string? FindCountProperty(WellKnownTypes types, SymbolAccessor symbolAccessor, ITypeSymbol t, CollectionType typeInfo) + private static string? FindCountProperty(SymbolAccessor symbolAccessor, ITypeSymbol t, CollectionType typeInfo) { if (typeInfo is CollectionType.IEnumerable) return null; @@ -170,7 +179,7 @@ or CollectionType.ReadOnlyMemory var member = symbolAccessor .GetAllAccessibleMappableMembers(t) .FirstOrDefault( - x => x.Name is nameof(ICollection.Count) or nameof(Array.Length) && x.Type.SpecialType == SpecialType.System_Int32 + x => x.Type.SpecialType == SpecialType.System_Int32 && x.Name is nameof(ICollection.Count) or nameof(Array.Length) ); return member?.Name; } diff --git a/src/Riok.Mapperly/Descriptors/SymbolAccessor.cs b/src/Riok.Mapperly/Descriptors/SymbolAccessor.cs index 7acc89d93c..c15a6eb52f 100644 --- a/src/Riok.Mapperly/Descriptors/SymbolAccessor.cs +++ b/src/Riok.Mapperly/Descriptors/SymbolAccessor.cs @@ -22,8 +22,13 @@ internal IEnumerable GetAttributes(ISymbol symbol) where T : Attribute { var attributeSymbol = _types.Get(); - return GetAttributesCore(symbol) - .Where(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass?.ConstructedFrom ?? x.AttributeClass, attributeSymbol)); + foreach (var attr in GetAttributesCore(symbol)) + { + if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.ConstructedFrom ?? attr.AttributeClass, attributeSymbol)) + { + yield return attr; + } + } } internal bool HasAttribute(ISymbol symbol) @@ -67,7 +72,13 @@ internal IReadOnlyCollection GetAllAccessibleMappableMembers(IT internal IEnumerable GetMappableMembers(ITypeSymbol symbol, string name, IEqualityComparer comparer) { - return GetAllAccessibleMappableMembers(symbol).Where(x => comparer.Equals(name, x.Name)); + foreach (var member in GetAllAccessibleMappableMembers(symbol)) + { + if (comparer.Equals(name, member.Name)) + { + yield return member; + } + } } private IEnumerable GetAllMembers(ITypeSymbol symbol, string name) => GetAllMembers(symbol).Where(x => name.Equals(x.Name)); diff --git a/src/Riok.Mapperly/Helpers/NullableSymbolExtensions.cs b/src/Riok.Mapperly/Helpers/NullableSymbolExtensions.cs index 827879c994..ba051e46d3 100644 --- a/src/Riok.Mapperly/Helpers/NullableSymbolExtensions.cs +++ b/src/Riok.Mapperly/Helpers/NullableSymbolExtensions.cs @@ -5,8 +5,6 @@ namespace Riok.Mapperly.Helpers; public static class NullableSymbolExtensions { - private const string NullableGenericTypeName = "System.Nullable"; - internal static bool HasSameOrStricterNullability(this ITypeSymbol symbol, ITypeSymbol other) { return symbol.NullableAnnotation == NullableAnnotation.NotAnnotated @@ -109,10 +107,7 @@ internal static bool IsNullable(this ITypeParameterSymbol typeParameter, Nullabl private static ITypeSymbol? NonNullableValueType(this ITypeSymbol symbol) { - if ( - symbol is INamedTypeSymbol { IsValueType: true, IsGenericType: true } namedType - && namedType.ConstructedFrom.ToDisplayString() == NullableGenericTypeName - ) + if (symbol.IsValueType && symbol is INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T } namedType) return namedType.TypeArguments[0]; return null; } diff --git a/src/Riok.Mapperly/Helpers/SymbolExtensions.cs b/src/Riok.Mapperly/Helpers/SymbolExtensions.cs index e9a591716f..ef5f1c99a2 100644 --- a/src/Riok.Mapperly/Helpers/SymbolExtensions.cs +++ b/src/Riok.Mapperly/Helpers/SymbolExtensions.cs @@ -70,10 +70,17 @@ internal static bool ImplementsGeneric( return true; } - typedInterface = t.AllInterfaces.FirstOrDefault( - x => x.IsGenericType && SymbolEqualityComparer.Default.Equals(x.OriginalDefinition, genericInterfaceSymbol) - ); - return typedInterface != null; + foreach (var typeSymbol in t.AllInterfaces) + { + if (typeSymbol.IsGenericType && SymbolEqualityComparer.Default.Equals(typeSymbol.OriginalDefinition, genericInterfaceSymbol)) + { + typedInterface = typeSymbol; + return true; + } + } + + typedInterface = null; + return false; } internal static bool ImplementsGeneric(