Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Enable Nullable on YamlSerialization project #10421

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions src/Docfx.YamlSerialization/Docfx.YamlSerialization.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="YamlDotNet" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Docfx.YamlSerialization/ExtensibleMemberAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ public sealed class ExtensibleMemberAttribute : Attribute
public string Prefix { get; }

public ExtensibleMemberAttribute()
: this(null)
: this(string.Empty)
{
}

public ExtensibleMemberAttribute(string prefix)
{
Prefix = prefix ?? string.Empty;
Prefix = prefix;
}
}
2 changes: 1 addition & 1 deletion src/Docfx.YamlSerialization/Helpers/ReflectionUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Docfx.YamlSerialization.Helpers;

internal static class ReflectionUtility
{
public static Type GetImplementedGenericInterface(Type type, Type genericInterfaceType)
public static Type? GetImplementedGenericInterface(Type type, Type genericInterfaceType)
{
foreach (var interfaceType in GetImplementedInterfaces(type))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ namespace Docfx.YamlSerialization.NodeDeserializers;
public class EmitArrayNodeDeserializer : INodeDeserializer
{
private static readonly MethodInfo DeserializeHelperMethod =
typeof(EmitArrayNodeDeserializer).GetMethod(nameof(DeserializeHelper));
private static readonly ConcurrentDictionary<Type, Func<IParser, Type, Func<IParser, Type, object>, object>> _funcCache =
typeof(EmitArrayNodeDeserializer).GetMethod(nameof(DeserializeHelper))!;
private static readonly ConcurrentDictionary<Type, Func<IParser, Type, Func<IParser, Type, object?>, object?>> _funcCache =
new();

bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value)
{
if (!expectedType.IsArray)
{
Expand All @@ -31,22 +31,22 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IPars
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static TItem[] DeserializeHelper<TItem>(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer)
public static TItem[] DeserializeHelper<TItem>(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer)
{
var items = new List<TItem>();
EmitGenericCollectionNodeDeserializer.DeserializeHelper(reader, expectedType, nestedObjectDeserializer, items);
return items.ToArray();
}

private static Func<IParser, Type, Func<IParser, Type, object>, object> AddItem(Type expectedType)
private static Func<IParser, Type, Func<IParser, Type, object?>, object?> AddItem(Type expectedType)
{
var dm = new DynamicMethod(string.Empty, typeof(object), [typeof(IParser), typeof(Type), typeof(Func<IParser, Type, object>)]);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(expectedType.GetElementType()));
il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(expectedType.GetElementType()!));
il.Emit(OpCodes.Ret);
return (Func<IParser, Type, Func<IParser, Type, object>, object>)dm.CreateDelegate(typeof(Func<IParser, Type, Func<IParser, Type, object>, object>));
return (Func<IParser, Type, Func<IParser, Type, object?>, object?>)dm.CreateDelegate(typeof(Func<IParser, Type, Func<IParser, Type, object?>, object?>));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ namespace Docfx.YamlSerialization.NodeDeserializers;
public class EmitGenericCollectionNodeDeserializer : INodeDeserializer
{
private static readonly MethodInfo DeserializeHelperMethod =
typeof(EmitGenericCollectionNodeDeserializer).GetMethod(nameof(DeserializeHelper));
typeof(EmitGenericCollectionNodeDeserializer).GetMethod(nameof(DeserializeHelper))!;
private readonly IObjectFactory _objectFactory;
private readonly Dictionary<Type, Type> _gpCache =
private readonly Dictionary<Type, Type?> _gpCache =
new();
private readonly Dictionary<Type, Action<IParser, Type, Func<IParser, Type, object>, object>> _actionCache =
private readonly Dictionary<Type, Action<IParser, Type, Func<IParser, Type, object?>, object?>> _actionCache =
new();

public EmitGenericCollectionNodeDeserializer(IObjectFactory objectFactory)
{
_objectFactory = objectFactory;
}

bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value)
{
if (!_gpCache.TryGetValue(expectedType, out Type gp))
if (!_gpCache.TryGetValue(expectedType, out var gp))
{
var collectionType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>));
if (collectionType != null)
Expand Down Expand Up @@ -66,7 +66,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IPars
il.Emit(OpCodes.Castclass, typeof(ICollection<>).MakeGenericType(gp));
il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(gp));
il.Emit(OpCodes.Ret);
action = (Action<IParser, Type, Func<IParser, Type, object>, object>)dm.CreateDelegate(typeof(Action<IParser, Type, Func<IParser, Type, object>, object>));
action = (Action<IParser, Type, Func<IParser, Type, object?>, object?>)dm.CreateDelegate(typeof(Action<IParser, Type, Func<IParser, Type, object?>, object?>));
_actionCache[gp] = action;
}

Expand All @@ -75,13 +75,11 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IPars
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static void DeserializeHelper<TItem>(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, ICollection<TItem> result)
public static void DeserializeHelper<TItem>(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, ICollection<TItem> result)
{
reader.Consume<SequenceStart>();
while (!reader.Accept<SequenceEnd>(out _))
{
var current = reader.Current;

var value = nestedObjectDeserializer(reader, typeof(TItem));
if (value is not IValuePromise promise)
{
Expand All @@ -90,11 +88,12 @@ public static void DeserializeHelper<TItem>(IParser reader, Type expectedType, F
else if (result is IList<TItem> list)
{
var index = list.Count;
result.Add(default);
result.Add(default!);
promise.ValueAvailable += v => list[index] = TypeConverter.ChangeType<TItem>(v, NullNamingConvention.Instance);
}
else
{
var current = reader.Current!;
throw new ForwardAnchorNotSupportedException(
current.Start,
current.End,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ namespace Docfx.YamlSerialization.NodeDeserializers;
public class EmitGenericDictionaryNodeDeserializer : INodeDeserializer
{
private static readonly MethodInfo DeserializeHelperMethod =
typeof(EmitGenericDictionaryNodeDeserializer).GetMethod(nameof(DeserializeHelper));
typeof(EmitGenericDictionaryNodeDeserializer).GetMethod(nameof(DeserializeHelper))!;
private readonly IObjectFactory _objectFactory;
private readonly Dictionary<Type, Type[]> _gpCache =
private readonly Dictionary<Type, Type[]?> _gpCache =
new();
private readonly Dictionary<Tuple<Type, Type>, Action<IParser, Type, Func<IParser, Type, object>, object>> _actionCache =
private readonly Dictionary<Tuple<Type, Type>, Action<IParser, Type, Func<IParser, Type, object?>, object?>> _actionCache =
new();

public EmitGenericDictionaryNodeDeserializer(IObjectFactory objectFactory)
{
_objectFactory = objectFactory;
}

bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value)
{
if (!_gpCache.TryGetValue(expectedType, out Type[] gp))
if (!_gpCache.TryGetValue(expectedType, out var gp))
{
var dictionaryType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<,>));
if (dictionaryType != null)
Expand Down Expand Up @@ -67,7 +67,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IPars
il.Emit(OpCodes.Castclass, typeof(IDictionary<,>).MakeGenericType(gp));
il.Emit(OpCodes.Call, DeserializeHelperMethod.MakeGenericMethod(gp));
il.Emit(OpCodes.Ret);
action = (Action<IParser, Type, Func<IParser, Type, object>, object>)dm.CreateDelegate(typeof(Action<IParser, Type, Func<IParser, Type, object>, object>));
action = (Action<IParser, Type, Func<IParser, Type, object?>, object?>)dm.CreateDelegate(typeof(Action<IParser, Type, Func<IParser, Type, object?>, object?>));
_actionCache[cacheKey] = action;
}
action(reader, expectedType, nestedObjectDeserializer, value);
Expand All @@ -78,7 +78,7 @@ bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IPars
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static void DeserializeHelper<TKey, TValue>(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, IDictionary<TKey, TValue> result)
public static void DeserializeHelper<TKey, TValue>(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, IDictionary<TKey, TValue> result)
{
while (!reader.Accept<MappingEnd>(out _))
{
Expand All @@ -92,20 +92,20 @@ public static void DeserializeHelper<TKey, TValue>(IParser reader, Type expected
if (valuePromise == null)
{
// Happy path: both key and value are known
result[(TKey)key] = (TValue)value;
result[(TKey)key!] = (TValue)value!;
}
else
{
// Key is known, value is pending
valuePromise.ValueAvailable += v => result[(TKey)key] = (TValue)v;
valuePromise.ValueAvailable += v => result[(TKey)key!] = (TValue)v!;
}
}
else
{
if (valuePromise == null)
{
// Key is pending, value is known
keyPromise.ValueAvailable += v => result[(TKey)v] = (TValue)value;
keyPromise.ValueAvailable += v => result[(TKey)v!] = (TValue)value!;
}
else
{
Expand All @@ -116,7 +116,7 @@ public static void DeserializeHelper<TKey, TValue>(IParser reader, Type expected
{
if (hasFirstPart)
{
result[(TKey)v] = (TValue)value;
result[(TKey)v!] = (TValue)value!;
}
else
{
Expand All @@ -129,7 +129,7 @@ public static void DeserializeHelper<TKey, TValue>(IParser reader, Type expected
{
if (hasFirstPart)
{
result[(TKey)key] = (TValue)v;
result[(TKey)key] = (TValue)v!;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ExtensibleObjectNodeDeserializer(IObjectFactory objectFactory, ITypeInspe
_ignoreUnmatched = ignoreUnmatched;
}

bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
bool INodeDeserializer.Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value)
{
if (!reader.TryConsume<MappingStart>(out _))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Docfx.YamlSerialization.NodeTypeResolvers;

internal sealed class ScalarYamlNodeTypeResolver : INodeTypeResolver
{
bool INodeTypeResolver.Resolve(NodeEvent nodeEvent, ref Type currentType)
bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType)
{
if (currentType == typeof(string) || currentType == typeof(object))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ namespace Docfx.YamlSerialization.ObjectDescriptors;

public class BetterObjectDescriptor : IObjectDescriptor
{
public BetterObjectDescriptor(object value, Type type, Type staticType)
public BetterObjectDescriptor(object? value, Type type, Type staticType)
: this(value, type, staticType, ScalarStyle.Any)
{
}

public BetterObjectDescriptor(object value, Type type, Type staticType, ScalarStyle scalarStyle)
public BetterObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle)
{
Value = value;
Type = type;
StaticType = staticType;
ScalarStyle = scalarStyle == ScalarStyle.Any && NeedQuote(value) ? ScalarStyle.DoubleQuoted : scalarStyle;

static bool NeedQuote(object val)
static bool NeedQuote(object? val)
{
if (val is not string s)
if (val is not string s || s == null)
return false;

return Regexes.BooleanLike().IsMatch(s)
Expand All @@ -42,5 +42,5 @@ static bool NeedQuote(object val)

public Type Type { get; }

public object Value { get; }
public object? Value { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ public class DefaultEmitObjectFactory : ObjectFactoryBase

public override object Create(Type type)
{
if (!_cache.TryGetValue(type, out Func<object> func))
if (!_cache.TryGetValue(type, out var func))
{
var realType = type;
if (type is {IsInterface: true, IsGenericType: true})
if (type is { IsInterface: true, IsGenericType: true })
{
var def = type.GetGenericTypeDefinition();
var args = type.GetGenericArguments();
Expand Down Expand Up @@ -46,7 +46,12 @@ public override object Create(Type type)
{
func = CreateValueTypeFactory(type);
}
_cache[type] = func;
else
{
throw new InvalidOperationException($"Failed to gets type instance create func for type: {type.FullName}.");
}

_cache[type] = func!;
}
return func();
}
Expand All @@ -56,7 +61,7 @@ private static Func<object> CreateReferenceTypeFactory(ConstructorInfo ctor)
var dm = new DynamicMethod(string.Empty, typeof(object), EmptyTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Newobj, ctor);
if (ctor.DeclaringType.IsValueType)
if (ctor.DeclaringType!.IsValueType)
{
il.Emit(OpCodes.Box, ctor.DeclaringType);
}
Expand Down
Loading