Skip to content

Commit

Permalink
[generator] Use decl type's @deprecated-since if < member's (#1068)
Browse files Browse the repository at this point in the history
Context: https://discord.com/channels/732297728826277939/732297837953679412/1052239604905934848

Imagine a type is deprecated in API-25 but its members were not
explicitly marked as deprecated:

	@deprecated
	public class TabActivity extends ActivityGroup {
	  public void setDefaultTab(String tag) { ... }
	}

Then in API-29 the member is explicitly marked as deprecated:

	@deprecated
	public class TabActivity extends ActivityGroup {
	  @deprecated
	  public void setDefaultTab(String tag) { ... }
	}

Due to the way `api-merge` calculates `@deprecated-since`, these
would end up with different values, with a resulting C# API:

	[ObsoletedOSPlatform("android25.0")]
	public class TabActivity : ActivityGroup
	{
	    [ObsoletedOSPlatform("android29.0")]
	    public void SetDefaultTab (string tag) { ... }
	}

While technically "fine", it is confusing that the method says it was
obsoleted in API-29 instead of API-25.

To fix this, if a member has a "higher" `@deprecated-since` value
than its declaring type, we set the member's `@deprecated-since`
value to the declaring type's `@deprecated-since` value.
  • Loading branch information
jpobst committed Dec 14, 2022
1 parent 525a45d commit 15c8879
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
3 changes: 1 addition & 2 deletions tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
</package>
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
<class abstract='false' deprecated='This is a class deprecated since 19!' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;' deprecated-since='19'>
<class abstract='false' deprecated='This is a class deprecated since 28!' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;' deprecated-since='28'>
<field deprecated='This is a field deprecated since 0!' final='true' name='ACCEPT_HANDOVER' jni-signature='Ljava/lang/String;' static='true' transient='false' type='java.lang.String' type-generic-aware='java.lang.String' value='&quot;android.permission.ACCEPT_HANDOVER&quot;' visibility='public' volatile='false' deprecated-since='0'></field>
<constructor deprecated='This is a constructor deprecated since empty string!' final='false' name='MyClass' jni-signature='()V' bridge='false' static='false' type='com.xamarin.android.MyClass' synthetic='false' visibility='public' deprecated-since=''></constructor>
<method abstract='true' deprecated='deprecated' final='false' name='countAffectedRows' jni-signature='()I' bridge='false' native='false' return='int' jni-return='I' static='false' synchronized='false' synthetic='false' visibility='public' deprecated-since='25'></method>
Expand All @@ -599,7 +599,6 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
generator.Context.ContextTypes.Pop ();

// These should use [Obsolete] because they have always been obsolete in all currently supported versions (21+)
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a class deprecated since 19!\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a field deprecated since 0!\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a constructor deprecated since empty string!\")]"), writer.ToString ());

Expand Down
27 changes: 27 additions & 0 deletions tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ public void CreateCtor_CorrectApiSinceFromClass ()
Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince);
}

[Test]
public void CreateCtor_CorrectDeprecatedSinceFromClass ()
{
var xml = XDocument.Parse ("<package name='com.example.test' jni-name='com/example/test'><class name='test' deprecated-since='7'><constructor name='ctor' deprecated-since='17' /></class></package>");
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);

Assert.AreEqual (7, klass.Ctors [0].DeprecatedSince);
}

[Test]
public void CreateField_StudlyCaseName ()
{
Expand Down Expand Up @@ -138,6 +147,15 @@ public void CreateField_CorrectApiVersionFromClass ()
Assert.AreEqual (7, field.ApiAvailableSince);
}

[Test]
public void CreateField_CorrectDeprecatedSinceFromClass ()
{
var xml = XDocument.Parse ("<package name='com.example.test' jni-name='com/example/test'><class name='test' deprecated-since='7'><field name='$3' deprecated-since='17' /></class></package>");
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);

Assert.AreEqual (7, klass.Fields [0].DeprecatedSince);
}

[Test]
public void CreateInterface_EnsureValidName ()
{
Expand Down Expand Up @@ -212,6 +230,15 @@ public void CreateMethod_CorrectApiSinceFromClass ()
Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince);
}

[Test]
public void CreateMethod_CorrectDeprecatedSinceFromClass ()
{
var xml = XDocument.Parse ("<package name='com.example.test' jni-name='com/example/test'><class name='test' deprecated-since='7'><method name='-3' deprecated-since='17' /></class></package>");
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);

Assert.AreEqual (7, klass.Methods [0].DeprecatedSince);
}

[Test]
public void CreateParameter_EnsureValidName ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ public static Ctor CreateCtor (GenBase declaringType, XElement elem, CodeGenerat

ctor.Name = EnsureValidIdentifer (ctor.Name);

// If declaring type was deprecated earlier than member, use the type's deprecated-since
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < ctor.DeprecatedSince.GetValueOrDefault (0))
ctor.DeprecatedSince = declaringType.DeprecatedSince;

FillApiSince (ctor, elem);

return ctor;
Expand Down Expand Up @@ -230,6 +234,10 @@ public static Field CreateField (GenBase declaringType, XElement elem, CodeGener
field.Name = EnsureValidIdentifer (field.Name);
}

// If declaring type was deprecated earlier than member, use the type's deprecated-since
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < field.DeprecatedSince.GetValueOrDefault (0))
field.DeprecatedSince = declaringType.DeprecatedSince;

FillApiSince (field, elem);
SetLineInfo (field, elem, options);

Expand Down Expand Up @@ -398,6 +406,10 @@ public static Method CreateMethod (GenBase declaringType, XElement elem, CodeGen

method.FillReturnType ();

// If declaring type was deprecated earlier than member, use the type's deprecated-since
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < method.DeprecatedSince.GetValueOrDefault (0))
method.DeprecatedSince = declaringType.DeprecatedSince;

FillApiSince (method, elem);
SetLineInfo (method, elem, options);

Expand Down

0 comments on commit 15c8879

Please sign in to comment.