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

[C#] Enable nullability for variant classes #82983

Merged
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
7 changes: 5 additions & 2 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using System.Runtime.CompilerServices;
using Godot.NativeInterop;

#nullable enable

namespace Godot.Collections
{
/// <summary>
Expand All @@ -22,7 +24,7 @@ public sealed class Array :
{
internal godot_array.movable NativeValue;

private WeakReference<IDisposable> _weakReferenceToSelf;
private WeakReference<IDisposable>? _weakReferenceToSelf;

/// <summary>
/// Constructs a new empty <see cref="Array"/>.
Expand Down Expand Up @@ -1140,7 +1142,8 @@ internal static Array<T> CreateTakingOwnershipOfDisposableValue(godot_array nati
/// </summary>
/// <param name="from">The typed array to convert.</param>
/// <returns>A new Godot Array, or <see langword="null"/> if <see paramref="from"/> was null.</returns>
public static explicit operator Array(Array<T> from)
[return: NotNullIfNotNull(nameof(from))]
public static explicit operator Array?(Array<T>? from)
{
return from?._underlyingArray;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ internal static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_n

var native = GodotObject.InternalGetClassNativeBase(scriptType);

var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
var field = native.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic);

if (field == null)
Expand Down Expand Up @@ -253,11 +253,15 @@ internal static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
{
var editorAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor");
wrapperType = editorAssembly?.GetType("Godot." + nativeTypeNameStr);

if (wrapperType == null)
if (editorAssembly != null)
{
wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr);
wrapperType = editorAssembly.GetType("Godot." + nativeTypeNameStr);

if (wrapperType == null)
{
wrapperType = GetTypeByGodotClassAttr(editorAssembly, nativeTypeNameStr);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ private static bool TryDeserializeSingleDelegate(byte[] buffer, [MaybeNullWhen(f
{
ulong objectId = reader.ReadUInt64();
// ReSharper disable once RedundantNameQualifier
GodotObject godotObject = GodotObject.InstanceFromId(objectId);
GodotObject? godotObject = GodotObject.InstanceFromId(objectId);
if (godotObject == null)
return false;

Expand Down
7 changes: 5 additions & 2 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Runtime.CompilerServices;
using Godot.NativeInterop;

#nullable enable

namespace Godot.Collections
{
/// <summary>
Expand All @@ -19,7 +21,7 @@ public sealed class Dictionary :
{
internal godot_dictionary.movable NativeValue;

private WeakReference<IDisposable> _weakReferenceToSelf;
private WeakReference<IDisposable>? _weakReferenceToSelf;

/// <summary>
/// Constructs a new empty <see cref="Dictionary"/>.
Expand Down Expand Up @@ -559,7 +561,8 @@ internal static Dictionary<TKey, TValue> CreateTakingOwnershipOfDisposableValue(
/// </summary>
/// <param name="from">The typed dictionary to convert.</param>
/// <returns>A new Godot Dictionary, or <see langword="null"/> if <see paramref="from"/> was null.</returns>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
[return: NotNullIfNotNull(nameof(from))]
public static explicit operator Dictionary?(Dictionary<TKey, TValue>? from)
{
return from?._underlyingDict;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using Godot.NativeInterop;

#nullable enable

namespace Godot
{
public partial class GodotObject
Expand All @@ -26,7 +28,7 @@ public partial class GodotObject
/// </example>
/// <param name="instanceId">Instance ID of the Object to retrieve.</param>
/// <returns>The <see cref="GodotObject"/> instance.</returns>
public static GodotObject InstanceFromId(ulong instanceId)
public static GodotObject? InstanceFromId(ulong instanceId)
{
return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId));
}
Expand All @@ -49,7 +51,7 @@ public static bool IsInstanceIdValid(ulong id)
/// </summary>
/// <param name="instance">The instance to check.</param>
/// <returns>If the instance is a valid object.</returns>
public static bool IsInstanceValid(GodotObject instance)
public static bool IsInstanceValid(GodotObject? instance)
{
return instance != null && instance.NativeInstance != IntPtr.Zero;
}
Expand All @@ -66,9 +68,9 @@ public static bool IsInstanceValid(GodotObject instance)
/// </summary>
/// <param name="obj">The object.</param>
/// <returns>
/// The <see cref="WeakRef"/> reference to the object or <see langword="null"/>.
/// The <see cref="Godot.WeakRef"/> reference to the object or <see langword="null"/>.
/// </returns>
public static WeakRef WeakRef(GodotObject obj)
public static WeakRef? WeakRef(GodotObject? obj)
{
if (!IsInstanceValid(obj))
return null;
Expand Down
23 changes: 11 additions & 12 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Godot.Bridge;
using Godot.NativeInterop;

#nullable enable

namespace Godot
{
public partial class GodotObject : IDisposable
Expand All @@ -13,7 +16,7 @@ public partial class GodotObject : IDisposable
internal IntPtr NativePtr;
private bool _memoryOwn;

private WeakReference<GodotObject> _weakReferenceToSelf;
private WeakReference<GodotObject>? _weakReferenceToSelf;

/// <summary>
/// Constructs a new <see cref="GodotObject"/>.
Expand Down Expand Up @@ -59,7 +62,7 @@ internal GodotObject(bool memoryOwn)
/// </summary>
public IntPtr NativeInstance => NativePtr;

internal static IntPtr GetPtr(GodotObject instance)
internal static IntPtr GetPtr(GodotObject? instance)
{
if (instance == null)
return IntPtr.Zero;
Expand Down Expand Up @@ -105,7 +108,7 @@ protected virtual void Dispose(bool disposing)

if (gcHandleToFree != IntPtr.Zero)
{
object target = GCHandle.FromIntPtr(gcHandleToFree).Target;
object? target = GCHandle.FromIntPtr(gcHandleToFree).Target;
// The GC handle may have been replaced in another thread. Release it only if
// it's associated to this managed instance, or if the target is no longer alive.
if (target != this && target != null)
Expand Down Expand Up @@ -176,18 +179,14 @@ public SignalAwaiter ToSignal(GodotObject source, StringName signal)

internal static Type InternalGetClassNativeBase(Type t)
{
do
{
var assemblyName = t.Assembly.GetName();
var name = t.Assembly.GetName().Name;

if (assemblyName.Name == "GodotSharp")
return t;
if (name == "GodotSharp" || name == "GodotSharpEditor")
return t;

if (assemblyName.Name == "GodotSharpEditor")
return t;
} while ((t = t.BaseType) != null);
Debug.Assert(t.BaseType is not null, "Script types must derive from a native Godot type.");

return null;
return InternalGetClassNativeBase(t.BaseType);
}

// ReSharper disable once VirtualMemberNeverOverridden.Global
Expand Down
18 changes: 11 additions & 7 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Godot.NativeInterop;

#nullable enable

namespace Godot
{
/// <summary>
Expand Down Expand Up @@ -39,11 +42,11 @@ namespace Godot
/// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
/// </code>
/// </example>
public sealed class NodePath : IDisposable, IEquatable<NodePath>
public sealed class NodePath : IDisposable, IEquatable<NodePath?>
{
internal godot_node_path.movable NativeValue;

private WeakReference<IDisposable> _weakReferenceToSelf;
private WeakReference<IDisposable>? _weakReferenceToSelf;

~NodePath()
{
Expand Down Expand Up @@ -135,7 +138,8 @@ public NodePath(string path)
/// Converts this <see cref="NodePath"/> to a string.
/// </summary>
/// <param name="from">The <see cref="NodePath"/> to convert.</param>
public static implicit operator string(NodePath from) => from?.ToString();
[return: NotNullIfNotNull(nameof(from))]
public static implicit operator string?(NodePath? from) => from?.ToString();

/// <summary>
/// Converts this <see cref="NodePath"/> to a string.
Expand Down Expand Up @@ -289,19 +293,19 @@ public bool IsAbsolute()
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;

public static bool operator ==(NodePath left, NodePath right)
public static bool operator ==(NodePath? left, NodePath? right)
{
if (left is null)
return right is null;
return left.Equals(right);
}

public static bool operator !=(NodePath left, NodePath right)
public static bool operator !=(NodePath? left, NodePath? right)
{
return !(left == right);
}

public bool Equals(NodePath other)
public bool Equals([NotNullWhen(true)] NodePath? other)
{
if (other is null)
return false;
Expand All @@ -310,7 +314,7 @@ public bool Equals(NodePath other)
return NativeFuncs.godotsharp_node_path_equals(self, otherNative).ToBool();
}

public override bool Equals(object obj)
public override bool Equals([NotNullWhen(true)] object? obj)
{
return ReferenceEquals(this, obj) || (obj is NodePath other && Equals(other));
}
Expand Down
26 changes: 15 additions & 11 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Godot.NativeInterop;

#nullable enable

namespace Godot
{
/// <summary>
Expand All @@ -10,11 +13,11 @@ namespace Godot
/// Comparing them is much faster than with regular strings, because only the pointers are compared,
/// not the whole strings.
/// </summary>
public sealed class StringName : IDisposable, IEquatable<StringName>
public sealed class StringName : IDisposable, IEquatable<StringName?>
{
internal godot_string_name.movable NativeValue;

private WeakReference<IDisposable> _weakReferenceToSelf;
private WeakReference<IDisposable>? _weakReferenceToSelf;

~StringName()
{
Expand Down Expand Up @@ -81,7 +84,8 @@ public StringName(string name)
/// Converts a <see cref="StringName"/> to a string.
/// </summary>
/// <param name="from">The <see cref="StringName"/> to convert.</param>
public static implicit operator string(StringName from) => from?.ToString();
[return: NotNullIfNotNull(nameof(from))]
public static implicit operator string?(StringName? from) => from?.ToString();

/// <summary>
/// Converts this <see cref="StringName"/> to a string.
Expand All @@ -104,43 +108,43 @@ public override string ToString()
/// <returns>If the <see cref="StringName"/> is empty.</returns>
public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;

public static bool operator ==(StringName left, StringName right)
public static bool operator ==(StringName? left, StringName? right)
{
if (left is null)
return right is null;
return left.Equals(right);
}

public static bool operator !=(StringName left, StringName right)
public static bool operator !=(StringName? left, StringName? right)
{
return !(left == right);
}

public bool Equals(StringName other)
public bool Equals([NotNullWhen(true)] StringName? other)
{
if (other is null)
return false;
return NativeValue.DangerousSelfRef == other.NativeValue.DangerousSelfRef;
}

public static bool operator ==(StringName left, in godot_string_name right)
public static bool operator ==(StringName? left, in godot_string_name right)
{
if (left is null)
return right.IsEmpty;
return left.Equals(right);
}

public static bool operator !=(StringName left, in godot_string_name right)
public static bool operator !=(StringName? left, in godot_string_name right)
{
return !(left == right);
}

public static bool operator ==(in godot_string_name left, StringName right)
public static bool operator ==(in godot_string_name left, StringName? right)
{
return right == left;
}

public static bool operator !=(in godot_string_name left, StringName right)
public static bool operator !=(in godot_string_name left, StringName? right)
{
return !(right == left);
}
Expand All @@ -150,7 +154,7 @@ public bool Equals(in godot_string_name other)
return NativeValue.DangerousSelfRef == other;
}

public override bool Equals(object obj)
public override bool Equals([NotNullWhen(true)] object? obj)
{
return ReferenceEquals(this, obj) || (obj is StringName other && Equals(other));
}
Expand Down
Loading