-
Notifications
You must be signed in to change notification settings - Fork 522
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
[coremidi] Add nullability to (generated and manual) bindings #15098
Conversation
get { | ||
return GetData (kMIDIPropertyConnectionUniqueID); | ||
} | ||
set { | ||
if (value is null) | ||
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I realize that I added a good amount of these and that SetData () throws an exception if the value arg is null, I thought it would be better to explicitly add the exceptions here and not use a !
, but I am open to opinions!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicit over implicit, I like it.
connectionParams.NumSources = (uint)Sources.Length; | ||
for (int i = 0; i < Sources.Length; i++) | ||
connectionParams.Sources[i] = Sources[i]; | ||
connectionParams.Sources [i] = Sources [i]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could possibly see this being a change in behavior since now it's possible that the connectionParams.NumSources
could not be set if the connectionParams.Sources is null
. I don't think that we want it to be set in that scenario anyways so either this is negligible, I can add a conditional around the for loop (but it looks messy), or I can just add an !
saying the connectionParams.Sources
is not null.
Same thing with the connectionParams.NumDestinations
a few lines below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is a breaking change:
- If Sources.Length is 0, then if NumSources isn't assigned there's no difference (because 0 is the default value)
- If Sources.Length > 0, then we'd run into a NullReferenceException in the loop.
So yes, there's a change in behavior, but from a NullReferenceException to no exception, which I think is fine in this scenario.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
connectionParams.NumSources = (uint)Sources.Length; | ||
for (int i = 0; i < Sources.Length; i++) | ||
connectionParams.Sources[i] = Sources[i]; | ||
connectionParams.Sources [i] = Sources [i]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is a breaking change:
- If Sources.Length is 0, then if NumSources isn't assigned there's no difference (because 0 is the default value)
- If Sources.Length > 0, then we'd run into a NullReferenceException in the loop.
So yes, there's a change in behavior, but from a NullReferenceException to no exception, which I think is fine in this scenario.
src/CoreMidi/MidiServices.cs
Outdated
@@ -758,7 +761,7 @@ public class MidiPacket | |||
#if !COREBUILD | |||
public long TimeStamp; | |||
IntPtr byteptr; | |||
byte [] bytes; | |||
byte []? bytes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting this to Array.Empty will remove a few things.
src/CoreMidi/MidiServices.cs
Outdated
using (var args = new MidiPacketsEventArgs (packetList)) { | ||
e (port, args); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the future, you can use using without the {} since it is small.
get { | ||
return GetData (kMIDIPropertyConnectionUniqueID); | ||
} | ||
set { | ||
if (value is null) | ||
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicit over implicit, I like it.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
📋 [PR Build] API Diff 📋API diff (for current PR)ℹ️ API Diff (from PR only) (please review changes) .NETXamarin vs .NETAPI diff (vs stable)✅ API Diff from stable .NETXamarin vs .NETGenerator diff✅ Generator Diff (no change) Pipeline on Agent XAMBOT-1033.Monterey' |
💻 [PR Build] Tests on macOS Mac Catalina (10.15) passed 💻✅ All tests on macOS Mac Catalina (10.15) passed. Pipeline on Agent |
if (e != null) { | ||
using (var args = new MidiPacketsEventArgs (packetList)) { | ||
e (port, args); | ||
if (gch.Target is MidiPort port) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is subtly different, as before a null gch.Target (or one of the wrong type) would throw, where this will silently no-op.
I think that is fine however.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes that is a good point!
using (var args = new MidiPacketsEventArgs (packetList)) | ||
e (port, args); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using (var args = new MidiPacketsEventArgs (packetList)) | |
e (port, args); | |
using (var args = new MidiPacketsEventArgs (packetList)) { | |
e (port, args); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think style wise we want braces for using blocks, but maybe I'm wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this block style as a request from Manuel
var e = port.MessageReceived; | ||
if (e != null) | ||
e (port, new MidiPacketsEventArgs (packetList)); | ||
if (gch.Target is MidiEndpoint port) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto comment above.
Unrelated Test Failure: https://github.com/xamarin/maccore/issues/2558 |
. (#16992) Closes #16979 The only `MidiPacket` constructor ever used internally is the one accepting an `IntPtr` argument. Therefore `bytes` will always have the default empty array value. Because of this, in the `Bytes` get accessor `bytes` is not null, but empty and indexing into `bytes` on line 848 throws the exception. The other option would have been to remove the empty array default value that was added in #15098, but the length check seemed like the safer, although maybe slightly less performant, option.
…ception. Fixes #16979. (#17022) Closes #16979 The only `MidiPacket` constructor ever used internally is the one accepting an `IntPtr` argument. Therefore `bytes` will always have the default empty array value. Because of this, in the `Bytes` get accessor `bytes` is not null, but empty and indexing into `bytes` on line 848 throws the exception. The other option would have been to remove the empty array default value that was added in #15098, but the length check seemed like the safer, although maybe slightly less performant, option. Backport of #16992 Co-authored-by: Reid Kirkpatrick <[email protected]>
Fixes #16979. (#17021) Closes #16979 The only `MidiPacket` constructor ever used internally is the one accepting an `IntPtr` argument. Therefore `bytes` will always have the default empty array value. Because of this, in the `Bytes` get accessor `bytes` is not null, but empty and indexing into `bytes` on line 848 throws the exception. The other option would have been to remove the empty array default value that was added in #15098, but the length check seemed like the safer, although maybe slightly less performant, option. Backport of #16992 Co-authored-by: Reid Kirkpatrick <[email protected]>
This PR aims to bring nullability changes to CoreMidi.
Following the steps here:
nullable enable
to all manual files that are not "API_SOURCES" in src/frameworks.sources and making the required nullability changesthrow new ArgumentNullException ("object"));
toObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (object));
for size saving optimization as well to mark that this framework contains nullability changes== null
or!= null
tois null
andis not null