Skip to content

Commit 15c8879

Browse files
authored
[generator] Use decl type's @deprecated-since if < member's (#1068)
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.
1 parent 525a45d commit 15c8879

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
576576
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
577577
</package>
578578
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
579-
<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'>
579+
<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'>
580580
<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>
581581
<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>
582582
<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>
@@ -599,7 +599,6 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
599599
generator.Context.ContextTypes.Pop ();
600600

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

tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ public void CreateCtor_CorrectApiSinceFromClass ()
7878
Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince);
7979
}
8080

81+
[Test]
82+
public void CreateCtor_CorrectDeprecatedSinceFromClass ()
83+
{
84+
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>");
85+
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);
86+
87+
Assert.AreEqual (7, klass.Ctors [0].DeprecatedSince);
88+
}
89+
8190
[Test]
8291
public void CreateField_StudlyCaseName ()
8392
{
@@ -138,6 +147,15 @@ public void CreateField_CorrectApiVersionFromClass ()
138147
Assert.AreEqual (7, field.ApiAvailableSince);
139148
}
140149

150+
[Test]
151+
public void CreateField_CorrectDeprecatedSinceFromClass ()
152+
{
153+
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>");
154+
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);
155+
156+
Assert.AreEqual (7, klass.Fields [0].DeprecatedSince);
157+
}
158+
141159
[Test]
142160
public void CreateInterface_EnsureValidName ()
143161
{
@@ -212,6 +230,15 @@ public void CreateMethod_CorrectApiSinceFromClass ()
212230
Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince);
213231
}
214232

233+
[Test]
234+
public void CreateMethod_CorrectDeprecatedSinceFromClass ()
235+
{
236+
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>");
237+
var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt);
238+
239+
Assert.AreEqual (7, klass.Methods [0].DeprecatedSince);
240+
}
241+
215242
[Test]
216243
public void CreateParameter_EnsureValidName ()
217244
{

tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ public static Ctor CreateCtor (GenBase declaringType, XElement elem, CodeGenerat
191191

192192
ctor.Name = EnsureValidIdentifer (ctor.Name);
193193

194+
// If declaring type was deprecated earlier than member, use the type's deprecated-since
195+
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < ctor.DeprecatedSince.GetValueOrDefault (0))
196+
ctor.DeprecatedSince = declaringType.DeprecatedSince;
197+
194198
FillApiSince (ctor, elem);
195199

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

237+
// If declaring type was deprecated earlier than member, use the type's deprecated-since
238+
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < field.DeprecatedSince.GetValueOrDefault (0))
239+
field.DeprecatedSince = declaringType.DeprecatedSince;
240+
233241
FillApiSince (field, elem);
234242
SetLineInfo (field, elem, options);
235243

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

399407
method.FillReturnType ();
400408

409+
// If declaring type was deprecated earlier than member, use the type's deprecated-since
410+
if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince.Value < method.DeprecatedSince.GetValueOrDefault (0))
411+
method.DeprecatedSince = declaringType.DeprecatedSince;
412+
401413
FillApiSince (method, elem);
402414
SetLineInfo (method, elem, options);
403415

0 commit comments

Comments
 (0)