Skip to content

Commit

Permalink
[Mono.Android] Add NRT annotations. (#4227)
Browse files Browse the repository at this point in the history
Context: dotnet/java-interop@01d0684

Annotates all API levels of `Mono.Android.dll` with
[C#8 Nullable Reference Type][0] (NRT) annotations, pulled directly
from the Java `.jar` files.

Additionally, our hand written code has been audited and updated to
include NRT annotations.

~~ Notes ~~

There are 8 new warnings caused by this change of the form:

	Android.Runtime/JavaDictionary.cs(655,24): warning CS8714: The type 'K' cannot be used as type parameter 'TKey' in the generic type or method 'IDictionary<TKey, TValue>'. Nullability of type argument 'K' doesn't match 'notnull' constraint.

This is due to the BCL being improperly annotated.  The change has
since been reverted, but it has not made it into various distribution
packs:

	dotnet/runtime#793

There are a considerable number of warnings (~400) caused by
mismatched annotations when members are overridden, such as:

	CS8610: Nullability of reference types in type of parameter 'baz' doesn't match overridden member.

While it may be desirable to fix these, it is a non-trivial job that
will be prioritized separately.

In the mean time, this set of warnings has been disabled:

	<NoWarn>8609;8610;8614;8617;8613;8764;8765;8766;8767</NoWarn>

Finally, when `$(AndroidGenerateJniMarshalMethods)`=True and
`jnimarshalmethod-gen.exe` is executed, the resulting app was crashing
because `MagicRegistrationMap.CallRegisterMethodByIndex()` had a
parameter change from `int` to `int?`.  Fix this by calling
`Nullable<int>.GetValueOrDefault()` with the `switch`.
`MonoDroidMarkStep.UpdateRegistrationSwitch()` now emits IL like:

	.method private hidebysig static bool
	        CallRegisterMethodByIndex([Java.Interop]Java.Interop.JniNativeMethodRegistrationArguments arguments,
	        [mscorlib]System.Nullable`1<int32> typeIdx) cil managed
	{
	  // Code size       9285 (0x2445)
	  .maxstack  2
	  .locals init ([mscorlib]System.Nullable`1<int32> V_0)
	  IL_0000:  ldarg.1
	  IL_0001:  stloc.0
	  IL_0002:  ldloca.s   V_0
	  IL_0004:  call       instance !0 [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
	  IL_0009:  switch     (
	  …

Co-authored-by: Radek Doulik <[email protected]>

[0]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
  • Loading branch information
jpobst authored Apr 23, 2020
1 parent a574834 commit d471b4a
Show file tree
Hide file tree
Showing 169 changed files with 1,327 additions and 1,129 deletions.
18 changes: 18 additions & 0 deletions Documentation/release-notes/4227.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#### Mono.Android.dll Nullable Reference Type Annotations

`Mono.Android.dll` assemblies of all platform levels are now annotated with
C#8's nullable reference types (NRT). Users who opt their applications into
this feature with `<Nullable>enable</Nullable>` will receive warnings if their
code does not properly account for possible `null` values.

General documentation for the NRT feature is available here:
https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references.

Note:
The majority of `Mono.Android.dll` is automatically generated from the Android
Java source, including these new annotations. As such, we will not be manually
fixing places where the Android source code is not annotated correctly.

If there is an error regarding nullability for any of the Mono.Android APIs
that Xamarin adds to the Android source (such as `JavaList` or `InputStreamAdapter`),
please file a bug so we can properly annotate our additions.
2 changes: 1 addition & 1 deletion external/Java.Interop
6 changes: 3 additions & 3 deletions src/Mono.Android/Android.Accounts/AccountManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace Android.Accounts {

public partial class AccountManager {

public static AccountManager FromContext (Context context)
public static AccountManager? FromContext (Context context)
{
return context.GetSystemService (Context.AccountService) as AccountManager;
}

WeakReference weak_implementor_AccountsUpdated;
WeakReference? weak_implementor_AccountsUpdated;
public event EventHandler<AccountsUpdateEventArgs> AccountsUpdated {
add {
AndroidEventHelper.AddEventHandler<IOnAccountsUpdateListener, IOnAccountsUpdateListenerImplementor>(
Expand All @@ -33,7 +33,7 @@ public event EventHandler<AccountsUpdateEventArgs> AccountsUpdated {
}
}

void SetOnAccountsUpdatedListener (IOnAccountsUpdateListener value)
void SetOnAccountsUpdatedListener (IOnAccountsUpdateListener? value)
{
AddOnAccountsUpdatedListener (value, null, false);
}
Expand Down
22 changes: 11 additions & 11 deletions src/Mono.Android/Android.Animation/Animator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ namespace Android.Animation {

partial class Animator {

WeakReference dispatcher;
WeakReference? dispatcher;
AnimatorEventDispatcher Dispatcher {
get {
if (dispatcher == null || !dispatcher.IsAlive) {
dispatcher = new WeakReference (new AnimatorEventDispatcher ());
AddListener ((AnimatorEventDispatcher) dispatcher.Target);
AddListener ((AnimatorEventDispatcher) dispatcher.Target!);
}
return (AnimatorEventDispatcher) dispatcher.Target;
return (AnimatorEventDispatcher) dispatcher.Target!;
}
}

Expand Down Expand Up @@ -67,33 +67,33 @@ public AnimatorEventDispatcher ()
JNIEnv.FinishCreateInstance (Handle, "()V");
}

public EventHandler AnimationCancel;
public EventHandler AnimationEnd;
public EventHandler AnimationRepeat;
public EventHandler AnimationStart;
public EventHandler? AnimationCancel;
public EventHandler? AnimationEnd;
public EventHandler? AnimationRepeat;
public EventHandler? AnimationStart;

public void OnAnimationCancel (Animator animation)
public void OnAnimationCancel (Animator? animation)
{
var h = AnimationCancel;
if (h != null)
h (animation, EventArgs.Empty);
}

public void OnAnimationEnd (Animator animation)
public void OnAnimationEnd (Animator? animation)
{
var h = AnimationEnd;
if (h != null)
h (animation, EventArgs.Empty);
}

public void OnAnimationRepeat (Animator animation)
public void OnAnimationRepeat (Animator? animation)
{
var h = AnimationRepeat;
if (h != null)
h (animation, EventArgs.Empty);
}

public void OnAnimationStart (Animator animation)
public void OnAnimationStart (Animator? animation)
{
var h = AnimationStart;
if (h != null)
Expand Down
8 changes: 4 additions & 4 deletions src/Mono.Android/Android.Animation/AnimatorSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ public override Animator SetDuration (long duration)
if (base.GetType () == this.ThresholdType) {
return Java.Lang.Object.GetObject<AnimatorSet> (
JNIEnv.CallObjectMethod (base.Handle, id_setDuration_J, new JValue (duration)),
JniHandleOwnership.TransferLocalRef);
JniHandleOwnership.TransferLocalRef)!;
} else {
return Java.Lang.Object.GetObject<AnimatorSet> (
JNIEnv.CallNonvirtualObjectMethod (
base.Handle,
this.ThresholdClass,
JNIEnv.GetMethodID (ThresholdClass, "setDuration", "(J)Landroid/animation/Animator;"),
new JValue (duration)),
JniHandleOwnership.TransferLocalRef);
JniHandleOwnership.TransferLocalRef)!;
}
}

private static Delegate cb_setDuration_J;
private static Delegate? cb_setDuration_J;

private static Delegate GetSetDuration_JHandler ()
{
Expand All @@ -40,7 +40,7 @@ private static Delegate GetSetDuration_JHandler ()

private static IntPtr n_SetDuration_J (IntPtr jnienv, IntPtr native__this, long duration)
{
AnimatorSet @object = Java.Lang.Object.GetObject<AnimatorSet> (native__this, JniHandleOwnership.DoNotTransfer);
AnimatorSet @object = Java.Lang.Object.GetObject<AnimatorSet> (native__this, JniHandleOwnership.DoNotTransfer)!;
return JNIEnv.ToJniHandle (@object.SetDuration (duration));
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.Animation/FloatArrayEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace Android.Animation
{
public partial class FloatArrayEvaluator
{
Object ITypeEvaluator.Evaluate (float fraction, Object startValue, Object endValue)
Object ITypeEvaluator.Evaluate (float fraction, Object? startValue, Object? endValue)
{
return new JavaArray<float> (JNIEnv.NewArray<float> (Evaluate (fraction, (float []) (JavaArray<float>) startValue, (float []) (JavaArray<float>) endValue)), JniHandleOwnership.TransferLocalRef);
return new JavaArray<float> (JNIEnv.NewArray<float> (Evaluate (fraction, (float []?) (JavaArray<float>?) startValue, (float []?) (JavaArray<float>?) endValue)), JniHandleOwnership.TransferLocalRef);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.Animation/FloatEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Android.Animation
{
public partial class FloatEvaluator
{
public virtual Object Evaluate (float fraction, Object startValue, Object endValue)
public virtual Object? Evaluate (float fraction, Object? startValue, Object? endValue)
{
return Evaluate (fraction, startValue.JavaCast<Number> (), endValue.JavaCast<Number> ());
}
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.Animation/IntArrayEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace Android.Animation
{
public partial class IntArrayEvaluator
{
Object ITypeEvaluator.Evaluate (float fraction, Object startValue, Object endValue)
Object ITypeEvaluator.Evaluate (float fraction, Object? startValue, Object? endValue)
{
return new JavaArray<int> (JNIEnv.NewArray<int> (Evaluate (fraction, (int []) (JavaArray<int>) startValue, (int []) (JavaArray<int>) endValue)), JniHandleOwnership.TransferLocalRef);
return new JavaArray<int> (JNIEnv.NewArray<int> (Evaluate (fraction, (int []?) (JavaArray<int>?) startValue, (int []?) (JavaArray<int>?) endValue)), JniHandleOwnership.TransferLocalRef);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.Animation/IntEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Android.Animation
{
public partial class IntEvaluator
{
public virtual Object Evaluate (float fraction, Object startValue, Object endValue)
public virtual Object? Evaluate (float fraction, Object? startValue, Object? endValue)
{
return Evaluate (fraction, startValue.JavaCast<Integer> (), endValue.JavaCast<Integer> ());
}
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.Animation/PointFEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace Android.Animation
{
public partial class PointFEvaluator
{
Object ITypeEvaluator.Evaluate (float fraction, Object startValue, Object endValue)
Object? ITypeEvaluator.Evaluate (float fraction, Object? startValue, Object? endValue)
{
return Evaluate (fraction, (PointF) startValue, (PointF) endValue);
return Evaluate (fraction, (PointF?) startValue, (PointF?) endValue);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.Animation/RectEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace Android.Animation
{
public partial class RectEvaluator
{
Object ITypeEvaluator.Evaluate (float fraction, Object startValue, Object endValue)
Object? ITypeEvaluator.Evaluate (float fraction, Object? startValue, Object? endValue)
{
return Evaluate (fraction, (Rect) startValue, (Rect) endValue);
return Evaluate (fraction, (Rect?) startValue, (Rect?) endValue);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/Mono.Android/Android.Animation/ValueAnimator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ public override Animator SetDuration (long duration)
if (base.GetType () == this.ThresholdType) {
return Java.Lang.Object.GetObject<ValueAnimator> (
JNIEnv.CallObjectMethod (base.Handle, id_setDuration_J, new JValue (duration)),
JniHandleOwnership.TransferLocalRef);
JniHandleOwnership.TransferLocalRef)!;
} else {
return Java.Lang.Object.GetObject<ValueAnimator> (
JNIEnv.CallNonvirtualObjectMethod (
base.Handle,
this.ThresholdClass,
JNIEnv.GetMethodID (ThresholdClass, "setDuration", "(J)Landroid/animation/Animator;"),
new JValue (duration)),
JniHandleOwnership.TransferLocalRef);
JniHandleOwnership.TransferLocalRef)!;
}
}

private static Delegate cb_setDuration_J;
private static Delegate? cb_setDuration_J;

private static Delegate GetSetDuration_JHandler ()
{
Expand All @@ -41,7 +41,7 @@ private static Delegate GetSetDuration_JHandler ()

private static IntPtr n_SetDuration_J (IntPtr jnienv, IntPtr native__this, long duration)
{
ValueAnimator @object = Java.Lang.Object.GetObject<ValueAnimator> (native__this, JniHandleOwnership.DoNotTransfer);
ValueAnimator @object = Java.Lang.Object.GetObject<ValueAnimator> (native__this, JniHandleOwnership.DoNotTransfer)!;
return JNIEnv.ToJniHandle (@object.SetDuration (duration));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.App.Admin/DevicePolicyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Android.App.Admin {

public partial class DevicePolicyManager {

public static DevicePolicyManager FromContext (Context context)
public static DevicePolicyManager? FromContext (Context context)
{
return context.GetSystemService (Context.DevicePolicyService) as DevicePolicyManager;
}
Expand Down
22 changes: 11 additions & 11 deletions src/Mono.Android/Android.App/ActionBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ partial class ActionBar {

public class TabEventArgs : EventArgs {

public TabEventArgs (FragmentTransaction fragmentTransaction)
public TabEventArgs (FragmentTransaction? fragmentTransaction)
{
FragmentTransaction = fragmentTransaction;
}

public FragmentTransaction FragmentTransaction {get; private set;}
public FragmentTransaction? FragmentTransaction {get; private set;}
}

partial class Tab {

WeakReference dispatcher;
WeakReference? dispatcher;
TabEventDispatcher Dispatcher {
get {
if (dispatcher == null || !dispatcher.IsAlive) {
dispatcher = new WeakReference (new TabEventDispatcher ());
SetTabListener ((TabEventDispatcher) dispatcher.Target);
SetTabListener ((TabEventDispatcher) dispatcher.Target!);
}
return (TabEventDispatcher) dispatcher.Target;
return (TabEventDispatcher) dispatcher.Target!;
}
}

Expand Down Expand Up @@ -71,25 +71,25 @@ public TabEventDispatcher ()
JNIEnv.FinishCreateInstance (Handle, "()V");
}

public EventHandler<ActionBar.TabEventArgs> TabReselected;
public EventHandler<ActionBar.TabEventArgs> TabSelected;
public EventHandler<ActionBar.TabEventArgs> TabUnselected;
public EventHandler<ActionBar.TabEventArgs>? TabReselected;
public EventHandler<ActionBar.TabEventArgs>? TabSelected;
public EventHandler<ActionBar.TabEventArgs>? TabUnselected;

public void OnTabReselected (ActionBar.Tab tab, FragmentTransaction ft)
public void OnTabReselected (ActionBar.Tab? tab, FragmentTransaction? ft)
{
var h = TabReselected;
if (h != null)
h (tab, new ActionBar.TabEventArgs (ft));
}

public void OnTabSelected (ActionBar.Tab tab, FragmentTransaction ft)
public void OnTabSelected (ActionBar.Tab? tab, FragmentTransaction? ft)
{
var h = TabSelected;
if (h != null)
h (tab, new ActionBar.TabEventArgs (ft));
}

public void OnTabUnselected (ActionBar.Tab tab, FragmentTransaction ft)
public void OnTabUnselected (ActionBar.Tab? tab, FragmentTransaction? ft)
{
var h = TabUnselected;
if (h != null)
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.App/Activity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace Android.App {

partial class Activity {

public T FindViewById<T> (int id)
public T? FindViewById<T> (int id)
where T : Android.Views.View
{
return this.FindViewById (id).JavaCast<T> ();
return this.FindViewById (id)!.JavaCast<T> ();
}

public void StartActivityForResult (Type activityType, int requestCode)
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.App/ActivityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Android.App {

public partial class ActivityManager {

public static ActivityManager FromContext (Context context)
public static ActivityManager? FromContext (Context context)
{
return context.GetSystemService (Context.ActivityService) as ActivityManager;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Mono.Android/Android.App/ActivityTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class ActivityTracker : Java.Lang.Object, Application.IActivityLifecycleCallback
{
readonly List<Activity> startedActivities = new List<Activity> ();

public event EventHandler ActivityStarted;
public event EventHandler? ActivityStarted;

public IReadOnlyList<Activity> StartedActivities {
get { return startedActivities; }
Expand All @@ -36,7 +36,7 @@ public void OnActivityStopped (Activity activity)
startedActivities.Remove (activity);
}

public void OnActivityCreated (Activity activity, Bundle savedInstanceState)
public void OnActivityCreated (Activity activity, Bundle? savedInstanceState)
{
}

Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.App/AlarmManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Android.App {

public partial class AlarmManager {

public static AlarmManager FromContext (Context context)
public static AlarmManager? FromContext (Context context)
{
return context.GetSystemService (Context.AlarmService) as AlarmManager;
}
Expand Down
Loading

0 comments on commit d471b4a

Please sign in to comment.