From 61b0a8ee7b2b5677527667691925cb041c53656a Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:11:37 -0700 Subject: [PATCH] perf: memoize type resolution per compilation; skip and source-generate JSON work GetTypeByMetadataName walks assemblies on every call, and the transforms resolved the same handful of names per field per class per compilation - tens of thousands of walks per keystroke at corpus scale. A per-compilation ConditionalWeakTable + ConcurrentDictionary cache collapses every call site (53) to a dictionary hit, including the migration augment stage's arbitrary schema type names. The augment stage also skips resolution entirely for properties without a save flag, since the value-type fact only affects the nullable suffix on save-flagged content struct fields. Migration JSON parsing and schema writing use a source-generated JsonSerializerContext, removing reflection-based metadata construction from the analyzer process. Benchmarks (150 classes): cold full run 29.9ms -> 6.5ms (3.2x faster than even the pre-#49 pipeline's 20.7ms), single-edit warm re-run 47.9ms -> 19.6ms, no-change re-run unchanged at ~64us. Output proven neutral: all snapshots byte-identical and the 3,786-source corpus manifest is unchanged. Co-Authored-By: Claude Fable 5 --- .../EntitySerializationGenerator.cs | 11 ++- ...SerializableEntityGeneration.BuildModel.cs | 4 +- .../MigrationJsonContext.cs | 29 ++++++++ .../SerializableMigrationSchema.cs | 3 +- .../SymbolMetadata/KnownTypeCache.cs | 45 +++++++++++ .../SymbolMetadata/SymbolMetadata.Builtin.cs | 26 +++---- .../SymbolMetadata/SymbolMetadata.UO.cs | 74 +++++++++---------- 7 files changed, 135 insertions(+), 57 deletions(-) create mode 100644 ModernUO.Serialization.Generator/SerializableMigration/MigrationJsonContext.cs create mode 100644 ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/KnownTypeCache.cs diff --git a/ModernUO.Serialization.Generator/EntitySerializationGenerator.cs b/ModernUO.Serialization.Generator/EntitySerializationGenerator.cs index c4d6204..5170514 100755 --- a/ModernUO.Serialization.Generator/EntitySerializationGenerator.cs +++ b/ModernUO.Serialization.Generator/EntitySerializationGenerator.cs @@ -123,11 +123,14 @@ CancellationToken token var builder = ImmutableArray.CreateBuilder(properties.Length); foreach (var property in properties) { + // The fact only affects the nullable suffix on save-flagged content struct fields. builder.Add( - property with - { - TypeIsValueType = compilation.GetTypeByMetadataName(property.Type)?.IsValueType == true - } + property.UsesSaveFlag != true + ? property + : property with + { + TypeIsValueType = compilation.GetCachedTypeByMetadataName(property.Type)?.IsValueType == true + } ); } diff --git a/ModernUO.Serialization.Generator/SerializableEntityGeneration/SerializableEntityGeneration.BuildModel.cs b/ModernUO.Serialization.Generator/SerializableEntityGeneration/SerializableEntityGeneration.BuildModel.cs index 15c2a22..252a071 100644 --- a/ModernUO.Serialization.Generator/SerializableEntityGeneration/SerializableEntityGeneration.BuildModel.cs +++ b/ModernUO.Serialization.Generator/SerializableEntityGeneration/SerializableEntityGeneration.BuildModel.cs @@ -378,7 +378,7 @@ SerializationModelResult Fail(DiagnosticDescriptor descriptor, params object[] a var invalidateProperties = allAttributes.Any( attr => attr.AttributeClass?.Equals( - compilation.GetTypeByMetadataName(SymbolMetadata.INVALIDATE_PROPERTIES_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SymbolMetadata.INVALIDATE_PROPERTIES_ATTRIBUTE), SymbolEqualityComparer.Default ) ?? false ); @@ -502,7 +502,7 @@ SerializationModelResult Fail(DiagnosticDescriptor descriptor, params object[] a .FirstOrDefault( a => SymbolEqualityComparer.Default.Equals( a.AttributeClass, - compilation.GetTypeByMetadataName(SymbolMetadata.AFTER_DESERIALIZATION_ATTRIBUTE) + compilation.GetCachedTypeByMetadataName(SymbolMetadata.AFTER_DESERIALIZATION_ATTRIBUTE) ) ); diff --git a/ModernUO.Serialization.Generator/SerializableMigration/MigrationJsonContext.cs b/ModernUO.Serialization.Generator/SerializableMigration/MigrationJsonContext.cs new file mode 100644 index 0000000..691caec --- /dev/null +++ b/ModernUO.Serialization.Generator/SerializableMigration/MigrationJsonContext.cs @@ -0,0 +1,29 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: MigrationJsonContext.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System.Text.Json.Serialization; + +namespace ModernUO.Serialization.Generator; + +/// +/// Source-generated serializer metadata for the migration schema types, so parsing thousands +/// of migration files never pays reflection-based metadata construction inside the analyzer +/// process. +/// +[JsonSerializable(typeof(SerializableMetadata))] +[JsonSerializable(typeof(SerializableProperty))] +internal partial class MigrationJsonContext : JsonSerializerContext +{ +} diff --git a/ModernUO.Serialization.Generator/SerializableMigration/SerializableMigrationSchema.cs b/ModernUO.Serialization.Generator/SerializableMigration/SerializableMigrationSchema.cs index 56bdabf..b2365c7 100644 --- a/ModernUO.Serialization.Generator/SerializableMigration/SerializableMigrationSchema.cs +++ b/ModernUO.Serialization.Generator/SerializableMigration/SerializableMigrationSchema.cs @@ -29,7 +29,8 @@ public static class SerializableMigrationSchema AllowTrailingCommas = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, ReadCommentHandling = JsonCommentHandling.Skip, - NewLine = "\n" // Force all json files to \n line endings + NewLine = "\n", // Force all json files to \n line endings + TypeInfoResolver = MigrationJsonContext.Default } ); diff --git a/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/KnownTypeCache.cs b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/KnownTypeCache.cs new file mode 100644 index 0000000..29f890c --- /dev/null +++ b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/KnownTypeCache.cs @@ -0,0 +1,45 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: KnownTypeCache.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; + +namespace ModernUO.Serialization.Generator; + +/// +/// Per-compilation memoization for , which +/// walks assemblies on every call. The transforms resolve the same handful of names per field +/// per class per compilation; this collapses those to dictionary hits. Keyed weakly so +/// discarded compilations do not pin their symbols. +/// +public static class KnownTypeCache +{ + private static readonly ConditionalWeakTable> _cache = + new(); + + public static INamedTypeSymbol GetCachedTypeByMetadataName(this Compilation compilation, string metadataName) + { + var types = _cache.GetOrCreateValue(compilation); + + if (!types.TryGetValue(metadataName, out var symbol)) + { + symbol = compilation.GetTypeByMetadataName(metadataName); + types.TryAdd(metadataName, symbol); + } + + return symbol; + } +} diff --git a/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.Builtin.cs b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.Builtin.cs index 6ae7506..3c7d09c 100644 --- a/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.Builtin.cs +++ b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.Builtin.cs @@ -38,63 +38,63 @@ public static partial class SymbolMetadata { public bool IsGuid(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(GUID_STRUCT), + compilation.GetCachedTypeByMetadataName(GUID_STRUCT), SymbolEqualityComparer.Default ); public bool IsTimeSpan(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(TIMESPAN_STRUCT), + compilation.GetCachedTypeByMetadataName(TIMESPAN_STRUCT), SymbolEqualityComparer.Default ); public bool IsIpAddress(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(IPADDRESS_CLASS), + compilation.GetCachedTypeByMetadataName(IPADDRESS_CLASS), SymbolEqualityComparer.Default ); public bool IsKeyValuePair(Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(KEYVALUEPAIR_STRUCT), + compilation.GetCachedTypeByMetadataName(KEYVALUEPAIR_STRUCT), SymbolEqualityComparer.Default ) == true; public bool IsDictionary(Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(DICTIONARY_CLASS), + compilation.GetCachedTypeByMetadataName(DICTIONARY_CLASS), SymbolEqualityComparer.Default ) == true; public bool IsDictionaryInterface(Compilation compilation) => - (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetTypeByMetadataName(DICTIONARY_INTERFACE)) ?? false; + (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetCachedTypeByMetadataName(DICTIONARY_INTERFACE)) ?? false; public bool IsHashSet(Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(HASHSET_CLASS), + compilation.GetCachedTypeByMetadataName(HASHSET_CLASS), SymbolEqualityComparer.Default ) == true; public bool IsSortedSet(Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(SORTEDSET_CLASS), + compilation.GetCachedTypeByMetadataName(SORTEDSET_CLASS), SymbolEqualityComparer.Default ) == true; public bool IsSet(Compilation compilation) => - (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetTypeByMetadataName(SET_INTERFACE)) ?? false; + (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetCachedTypeByMetadataName(SET_INTERFACE)) ?? false; public bool IsCollection(Compilation compilation) => - (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetTypeByMetadataName(COLLECTION_INTERFACE)) ?? false; + (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetCachedTypeByMetadataName(COLLECTION_INTERFACE)) ?? false; public bool IsList(Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(LIST_CLASS), + compilation.GetCachedTypeByMetadataName(LIST_CLASS), SymbolEqualityComparer.Default ) == true; public bool IsListInterface(Compilation compilation) => - (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetTypeByMetadataName(LIST_INTERFACE)) ?? false; + (symbol as INamedTypeSymbol)?.ContainsInterface(compilation.GetCachedTypeByMetadataName(LIST_INTERFACE)) ?? false; } public static bool IsPrimitiveFromTypeDisplayString(string type) => @@ -103,7 +103,7 @@ type is "bool" or "sbyte" or "short" or "int" or "long" or "byte" or "ushort" public static bool IsType(this ISymbol symbol, Compilation compilation) => (symbol as INamedTypeSymbol)?.ConstructedFrom.Equals( - compilation.GetTypeByMetadataName(TYPE_CLASS), + compilation.GetCachedTypeByMetadataName(TYPE_CLASS), SymbolEqualityComparer.Default ) == true; } diff --git a/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.UO.cs b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.UO.cs index cff5894..a764f12 100644 --- a/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.UO.cs +++ b/ModernUO.Serialization.Generator/SourceGeneration/SymbolMetadata/SymbolMetadata.UO.cs @@ -69,7 +69,7 @@ public bool IsSerializedPropertyAttr(Compilation compilation, out ITypeSymbol ge return false; } - var serializedPropertyAttrType = compilation.GetTypeByMetadataName(SERIALIZED_PROPERTY_ATTR_ATTRIBUTE); + var serializedPropertyAttrType = compilation.GetCachedTypeByMetadataName(SERIALIZED_PROPERTY_ATTR_ATTRIBUTE); if (!attrClass.BaseType.ConstructedFrom.Equals(serializedPropertyAttrType, SymbolEqualityComparer.Default)) { genericType = null; @@ -88,37 +88,37 @@ public bool IsSerializedPropertyAttr(Compilation compilation, out ITypeSymbol ge } public bool IsCanBeNull(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(CAN_BE_NULL_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(CAN_BE_NULL_ATTRIBUTE)) == true; public bool IsTimerDrift(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(TIMER_DRIFT_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(TIMER_DRIFT_ATTRIBUTE)) == true; } public static bool IsTimer(this ITypeSymbol symbol, Compilation compilation) => - symbol.CanBeConstructedFrom(compilation.GetTypeByMetadataName(TIMER_CLASS)); + symbol.CanBeConstructedFrom(compilation.GetCachedTypeByMetadataName(TIMER_CLASS)); extension(AttributeData attr) { public bool IsEncodedInt(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(ENCODED_INT_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(ENCODED_INT_ATTRIBUTE)) == true; public bool IsDeltaDateTime(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(DELTA_DATE_TIME_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(DELTA_DATE_TIME_ATTRIBUTE)) == true; public bool IsAnchoredDateTime(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(ANCHORED_DATE_TIME_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(ANCHORED_DATE_TIME_ATTRIBUTE)) == true; public bool IsInternString(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(INTERN_STRING_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(INTERN_STRING_ATTRIBUTE)) == true; public bool IsTidy(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(TIDY_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(TIDY_ATTRIBUTE)) == true; public bool IsAttribute(ISymbol symbol) => attr?.AttributeClass?.Equals(symbol, SymbolEqualityComparer.Default) == true; public bool IsSortedSetComparer(Compilation compilation) => - attr?.IsAttribute(compilation.GetTypeByMetadataName(SORTED_SET_COMPARER_ATTRIBUTE)) == true; + attr?.IsAttribute(compilation.GetCachedTypeByMetadataName(SORTED_SET_COMPARER_ATTRIBUTE)) == true; } public static bool TryGetSortedSetComparer( @@ -127,7 +127,7 @@ public static bool TryGetSortedSetComparer( out string? comparerExpression ) { - var sortedSetComparerAttr = compilation.GetTypeByMetadataName(SORTED_SET_COMPARER_ATTRIBUTE); + var sortedSetComparerAttr = compilation.GetCachedTypeByMetadataName(SORTED_SET_COMPARER_ATTRIBUTE); var attr = attributes.FirstOrDefault(a => a.IsAttribute(sortedSetComparerAttr)); if (attr == null) @@ -166,7 +166,7 @@ public bool IsEnum() => public bool HasSerializableInterface( Compilation compilation - ) => symbol.ContainsInterface(compilation.GetTypeByMetadataName(SERIALIZABLE_INTERFACE)); + ) => symbol.ContainsInterface(compilation.GetCachedTypeByMetadataName(SERIALIZABLE_INTERFACE)); } public static bool Contains(this ImmutableArray symbols, ITypeSymbol? symbol) => @@ -179,7 +179,7 @@ public bool HasSerialCtor( Compilation compilation ) { - var serialType = compilation.GetTypeByMetadataName(SERIAL_STRUCT); + var serialType = compilation.GetCachedTypeByMetadataName(SERIAL_STRUCT); return symbol.Constructors.FirstOrDefault( member => member.Parameters.Length == 1 @@ -243,7 +243,7 @@ public bool HasGenericReaderCtor( out bool requiresParent ) { - var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE); + var genericReaderInterface = compilation.GetCachedTypeByMetadataName(GENERIC_READER_INTERFACE); var genericCtor = symbol.Constructors.FirstOrDefault( m => !m.IsStatic && m.MethodKind == MethodKind.Constructor && @@ -338,7 +338,7 @@ public IMethodSymbol GetDeserializeTimerMethod(Compilation compilation, int orde { if (!SymbolEqualityComparer.Default.Equals( attr.AttributeClass, - compilation.GetTypeByMetadataName(DESERIALIZE_TIMER_FIELD_ATTRIBUTE) + compilation.GetCachedTypeByMetadataName(DESERIALIZE_TIMER_FIELD_ATTRIBUTE) )) { return false; @@ -353,7 +353,7 @@ public IMethodSymbol GetDeserializeTimerMethod(Compilation compilation, int orde public bool HasPublicSerializeMethod(Compilation compilation) { - var genericWriterInterface = compilation.GetTypeByMetadataName(GENERIC_WRITER_INTERFACE); + var genericWriterInterface = compilation.GetCachedTypeByMetadataName(GENERIC_WRITER_INTERFACE); return symbol.GetAllMethods("Serialize") .Any( @@ -369,7 +369,7 @@ public bool HasPublicDeserializeMethod( Compilation compilation ) { - var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE); + var genericReaderInterface = compilation.GetCachedTypeByMetadataName(GENERIC_READER_INTERFACE); return symbol.GetAllMethods("Deserialize") .Any( @@ -389,53 +389,53 @@ Compilation compilation extension(ISymbol symbol) { public bool IsTextDefinition(Compilation compilation) => - symbol.IsTypeRecurse(compilation, compilation.GetTypeByMetadataName(TEXTDEFINITION_CLASS)); + symbol.IsTypeRecurse(compilation, compilation.GetCachedTypeByMetadataName(TEXTDEFINITION_CLASS)); public bool IsPoison(Compilation compilation) => - symbol.IsTypeRecurse(compilation, compilation.GetTypeByMetadataName(POISON_CLASS)); + symbol.IsTypeRecurse(compilation, compilation.GetCachedTypeByMetadataName(POISON_CLASS)); public bool IsPoint2D(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(POINT2D_STRUCT), + compilation.GetCachedTypeByMetadataName(POINT2D_STRUCT), SymbolEqualityComparer.Default ); public bool IsPoint3D(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(POINT3D_STRUCT), + compilation.GetCachedTypeByMetadataName(POINT3D_STRUCT), SymbolEqualityComparer.Default ); public bool IsRectangle2D(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(RECTANGLE2D_STRUCT), + compilation.GetCachedTypeByMetadataName(RECTANGLE2D_STRUCT), SymbolEqualityComparer.Default ); public bool IsRectangle3D(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(RECTANGLE3D_STRUCT), + compilation.GetCachedTypeByMetadataName(RECTANGLE3D_STRUCT), SymbolEqualityComparer.Default ); public bool IsRace(Compilation compilation) => - symbol.IsTypeRecurse(compilation, compilation.GetTypeByMetadataName(RACE_CLASS)); + symbol.IsTypeRecurse(compilation, compilation.GetCachedTypeByMetadataName(RACE_CLASS)); public bool IsMap(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(MAP_CLASS), + compilation.GetCachedTypeByMetadataName(MAP_CLASS), SymbolEqualityComparer.Default ); public bool IsBitArray(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(BITARRAY_CLASS), + compilation.GetCachedTypeByMetadataName(BITARRAY_CLASS), SymbolEqualityComparer.Default ); public bool IsSerial(Compilation compilation) => symbol.Equals( - compilation.GetTypeByMetadataName(SERIAL_STRUCT), + compilation.GetCachedTypeByMetadataName(SERIAL_STRUCT), SymbolEqualityComparer.Default ); @@ -450,7 +450,7 @@ public bool IsSerial(Compilation compilation) => extension(INamedTypeSymbol classSymbol) { public bool HasSerializableInterface(Compilation compilation) => - classSymbol.ContainsInterface(compilation.GetTypeByMetadataName(SERIALIZABLE_INTERFACE)); + classSymbol.ContainsInterface(compilation.GetCachedTypeByMetadataName(SERIALIZABLE_INTERFACE)); public bool IsSerializableRecursive(Compilation compilation) => classSymbol.TryGetSerializable(compilation, out _) || @@ -461,7 +461,7 @@ public bool TryGetSerializable( ) { var serializableEntityAttribute = - compilation.GetTypeByMetadataName(SERIALIZABLE_ATTRIBUTE); + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_ATTRIBUTE); attributeData = classSymbol.GetAttribute(serializableEntityAttribute); return attributeData != null; @@ -481,40 +481,40 @@ public bool TryGetMemberWithAttribute( public bool TryGetSerializableField( Compilation compilation, out AttributeData? attributeData ) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(SERIALIZABLE_FIELD_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_FIELD_ATTRIBUTE), out attributeData ); public bool TryGetSerializableProperty( Compilation compilation, out AttributeData? attributeData ) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(SERIALIZABLE_PROPERTY_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_PROPERTY_ATTRIBUTE), out attributeData ); public bool TryGetDirtyTrackingEntityField(Compilation compilation) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(DIRTY_TRACKING_ENTITY_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(DIRTY_TRACKING_ENTITY_ATTRIBUTE), out _ ); public bool TryGetSerializableFieldSaveFlagMethod( Compilation compilation, out AttributeData? attributeData ) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE), out attributeData ); public bool TryGetSerializableFieldDefaultMethod( Compilation compilation, out AttributeData? attributeData ) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE), out attributeData ); public bool TryGetSerializableFieldChangedMethod(Compilation compilation, out AttributeData? attributeData) => symbol.TryGetMemberWithAttribute( - compilation.GetTypeByMetadataName(SERIALIZABLE_FIELD_CHANGED_ATTRIBUTE), + compilation.GetCachedTypeByMetadataName(SERIALIZABLE_FIELD_CHANGED_ATTRIBUTE), out attributeData ); } @@ -525,7 +525,7 @@ public bool HasStaticDeserializeFactory( Compilation compilation ) { - var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE); + var genericReaderInterface = compilation.GetCachedTypeByMetadataName(GENERIC_READER_INTERFACE); return symbol.GetMembers("Deserialize") .OfType() @@ -542,7 +542,7 @@ public bool HasInstanceDeserializeMethod( Compilation compilation ) { - var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE); + var genericReaderInterface = compilation.GetCachedTypeByMetadataName(GENERIC_READER_INTERFACE); return symbol.GetMembers("Deserialize") .OfType()