Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions ModernUO.Serialization.Generator/EntitySerializationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,14 @@ CancellationToken token
var builder = ImmutableArray.CreateBuilder<SerializableProperty>(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
}
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
Expand Down Expand Up @@ -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)
)
);

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. *
*************************************************************************/

using System.Text.Json.Serialization;

namespace ModernUO.Serialization.Generator;

/// <summary>
/// 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.
/// </summary>
[JsonSerializable(typeof(SerializableMetadata))]
[JsonSerializable(typeof(SerializableProperty))]
internal partial class MigrationJsonContext : JsonSerializerContext
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. *
*************************************************************************/

using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;

namespace ModernUO.Serialization.Generator;

/// <summary>
/// Per-compilation memoization for <see cref="Compilation.GetTypeByMetadataName" />, 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.
/// </summary>
public static class KnownTypeCache
{
private static readonly ConditionalWeakTable<Compilation, ConcurrentDictionary<string, INamedTypeSymbol>> _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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand All @@ -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;
}
Loading
Loading