Skip to content

Commit 8f30933

Browse files
authored
[generator] Mark some Obsolete fields as errors (#568)
Context: #509 Context: dotnet/android#4248 We are generating fields that have been marked as `[Obsolete]` for a long time. In the effort to remove all fields that now we believe should not be part of our API, we are marking them as `[Obsolete(..., error:true)]` so we can remove them in a future release. Here are some scenarios these changes are addressing: We should `[Obsolete(error:true)]` *fields* on "interface proxy" types such as [`Android.Content.ComponentCallbacks2`][0], which contains fields for the [`android.content.ComponentCallbacks2`][1] interface and lives "alongside" the [Android.Content.IComponentCallbacks2][2] interface. Additionally, all of these fields should *eventually* be moved into the appropriate C# interface via Default Interface Members, e.g. every field within `Android.Content.ComponentCallbacks2` should *instead* reside in the `Android.Content.IComponentCallbacks2` type. TODO: * We should `[Obsolete(error:true)]` the interface proxy types themselves. * We also `[Obsolete(error:true)]` all of the nested `InterfaceConsts` types, such as `Android.OS.Binder.InterfaceConsts`. * We should also `[Obsolete(error:true)]` all members which are already [Obsolete]. [0]: https://docs.microsoft.com/en-us/dotnet/api/android.content.componentcallbacks2?view=xamarin-android-sdk-9 [1]: https://developer.android.com/reference/android/content/ComponentCallbacks2 [2]: https://docs.microsoft.com/en-us/dotnet/api/android.content.icomponentcallbacks2?view=xamarin-android-sdk-9
1 parent 47201c4 commit 8f30933

File tree

10 files changed

+108
-38
lines changed

10 files changed

+108
-38
lines changed

.vscode/launch.json

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
{
2-
// Use IntelliSense to learn about possible attributes.
3-
// Hover to view descriptions of existing attributes.
4-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5-
"version": "0.2.0",
6-
"configurations": [
7-
{
8-
"name": "Launch",
9-
"type": "mono",
10-
"request": "launch",
11-
"program": "${workspaceRoot}/packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe ${workspaceRoot}/bin/TestDebug/generator-Tests.dll",
12-
"cwd": "${workspaceRoot}bin/TestDebug/"
13-
},
14-
{
15-
"name": "Attach",
16-
"type": "mono",
17-
"request": "attach",
18-
"address": "localhost",
19-
"port": 55555
20-
}
21-
]
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch",
9+
"type": "mono",
10+
"request": "launch",
11+
"program": "${workspaceRoot}/packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe ${workspaceRoot}/bin/TestDebug/generator-Tests.dll",
12+
"cwd": "${workspaceRoot}bin/TestDebug/"
13+
},
14+
{
15+
"name": "Attach",
16+
"type": "mono",
17+
"request": "attach",
18+
"address": "localhost",
19+
"port": 55555
20+
},
21+
{
22+
"name": "Launch Generator",
23+
"type": "mono",
24+
"request": "launch",
25+
"preLaunchTask": "Build Generator",
26+
"program": "${workspaceRoot}/bin/TestDebug/generator.exe",
27+
"args": [
28+
"--public",
29+
"--product-version=7",
30+
"--api-level=29",
31+
"-o=obj/Debug/android-29/mcw/",
32+
"--codegen-target=XAJavaInterop1",
33+
"--fixup=metadata",
34+
"--preserve-enums",
35+
"--enumflags=enumflags",
36+
"--enumfields=map.csv",
37+
"--enummethods=methodmap.csv",
38+
"--enummetadata=obj/Debug/android-29/mcw/enummetadata",
39+
"--apiversions=${env:HOME}/android-toolchain/sdk/platforms/android-29/data/api-versions.xml",
40+
"--annotations=${env:HOME}/android-toolchain/sdk/platforms/android-29/data/annotations.zip",
41+
"--type-map-report=obj/Debug/android-29/mcw/type-mapping.txt",
42+
"--enumdir=obj/Debug/android-29/mcw",
43+
"obj/Debug/android-29/mcw/api.xml"
44+
],
45+
"cwd": "${workspaceRoot}/../xamarin-android/src/Mono.Android",
46+
}
47+
]
2248
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,11 @@ public void WriteDeprecatedField ()
346346
{
347347
var comment = "Don't use this!";
348348
var @class = new TestClass ("java.lang.Object", "com.mypackage.foo");
349-
var field = new TestField ("int", "bar").SetConstant ("1234").SetDeprecated (comment);
349+
var field = new TestField ("int", "bar").SetConstant ("1234").SetDeprecated (comment, true);
350350
Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "field.Validate failed!");
351351
generator.WriteField (field, string.Empty, @class);
352352

353-
StringAssert.Contains ($"[Obsolete (\"{comment}\")]", builder.ToString (), "Should contain ObsoleteAttribute!");
353+
StringAssert.Contains ($"[Obsolete (\"{comment}\", error: true)]", builder.ToString (), "Should contain ObsoleteAttribute!");
354354
}
355355

356356
[Test]
@@ -535,7 +535,7 @@ public void WriteInterfaceEventArgs ()
535535
var iface = SupportTypeBuilder.CreateInterface ("java.code.IMyInterface", options);
536536

537537
generator.Context.ContextTypes.Push (iface);
538-
generator.WriteInterfaceEventArgs (iface, iface.Methods[0], string.Empty);
538+
generator.WriteInterfaceEventArgs (iface, iface.Methods [0], string.Empty);
539539
generator.Context.ContextTypes.Pop ();
540540

541541
Assert.AreEqual (GetExpected (nameof (WriteInterfaceEventArgs)), writer.ToString ().NormalizeLineEndings ());
@@ -572,7 +572,7 @@ public void WriteInterfaceEventHandlerImplContent ()
572572
var handlers = new List<string> ();
573573

574574
generator.Context.ContextTypes.Push (iface);
575-
generator.WriteInterfaceEventHandlerImplContent (iface, iface.Methods[0], string.Empty, true, string.Empty, handlers);
575+
generator.WriteInterfaceEventHandlerImplContent (iface, iface.Methods [0], string.Empty, true, string.Empty, handlers);
576576
generator.Context.ContextTypes.Pop ();
577577

578578
Assert.AreEqual (1, handlers.Count);

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ public TestField SetEnumified ()
6464
return this;
6565
}
6666

67-
public TestField SetDeprecated (string comment = null)
67+
public TestField SetDeprecated (string comment = null, bool error = false)
6868
{
6969
IsDeprecated = true;
70+
IsDeprecatedError = error;
7071
DeprecatedComment = comment;
7172
return this;
7273
}
@@ -280,7 +281,7 @@ public static TestInterface CreateInterface (string interfaceName, CodeGeneratio
280281
return iface;
281282
}
282283

283-
public static TestMethod CreateMethod (GenBase parent, string methodName, CodeGenerationOptions options, string returnType = "void", bool isStatic = false, bool isAbstract = false, params Parameter[] parameters)
284+
public static TestMethod CreateMethod (GenBase parent, string methodName, CodeGenerationOptions options, string returnType = "void", bool isStatic = false, bool isAbstract = false, params Parameter [] parameters)
284285
{
285286
var method = new TestMethod (parent, methodName, returnType);
286287

tests/generator-Tests/expected/EnumerationFixup/EnumerationFixup.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</class>
66
</package>
77
<package name="xamarin.test">
8-
<class abstract="false" deprecated="not deprecated" extends="java.lang.Object" extends-generic-aware="java.lang.Object"
8+
<class abstract="false" deprecated="not deprecated" extends="java.lang.Object" extends-generic-aware="java.lang.Object"
99
final="false" name="SomeObject" static="false" visibility="public">
1010
<field deprecated="not deprecated" final="true" name="SOME_VALUE" static="false" transient="false" type="Xamarin.Test.SomeValues" type-generic-aware="int" visibility="public" volatile="false">
1111
</field>
@@ -18,7 +18,7 @@
1818
</parameter>
1919
</method>
2020
</class>
21-
<class abstract="false" deprecated="not deprecated" extends="xamarin.test.SomeObject" extends-generic-aware="xamarin.test.SomeObject"
21+
<class abstract="false" deprecated="not deprecated" extends="xamarin.test.SomeObject" extends-generic-aware="xamarin.test.SomeObject"
2222
final="false" name="SomeObject2" static="false" visibility="public">
2323
<method abstract="false" deprecated="not deprecated" final="false" name="getSomeObjectProperty" native="false" return="int" enumReturn="Xamarin.Test.SomeValues" static="false" synchronized="false" visibility="public">
2424
</method>
@@ -33,6 +33,9 @@
3333
</parameter>
3434
</method>
3535
</class>
36+
<class abstract="false" deprecated="not deprecated" extends="java.lang.Object" extends-generic-aware="java.lang.Object" final="false" name="DeprecatedItems" static="false" visibility="public">
37+
<field deprecated="Field is deprecated" deprecated-error="true" final="true" name="My_Test_Field" jni-signature="I" static="true" transient="false" type="int" type-generic-aware="int" value="1" visibility="public" volatile="false" />
38+
</class>
3639
</package>
3740
<enum name="Xamarin.Test.SomeValues"/>
3841
</api>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Android.Runtime;
4+
5+
namespace Xamarin.Test {
6+
7+
// Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='DeprecatedItems']"
8+
[global::Android.Runtime.Register ("xamarin/test/DeprecatedItems", DoNotGenerateAcw=true)]
9+
public partial class DeprecatedItems : global::Java.Lang.Object {
10+
11+
12+
// Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='DeprecatedItems']/field[@name='My_Test_Field']"
13+
[Register ("My_Test_Field")]
14+
[Obsolete ("Field is deprecated", error: true)]
15+
public const int MyTestField = (int) 1;
16+
internal static new IntPtr java_class_handle;
17+
internal static new IntPtr class_ref {
18+
get {
19+
return JNIEnv.FindClass ("xamarin/test/DeprecatedItems", ref java_class_handle);
20+
}
21+
}
22+
23+
protected override IntPtr ThresholdClass {
24+
get { return class_ref; }
25+
}
26+
27+
protected override global::System.Type ThresholdType {
28+
get { return typeof (DeprecatedItems); }
29+
}
30+
31+
protected DeprecatedItems (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {}
32+
33+
}
34+
}

tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,10 @@ internal virtual void WriteField (Field field, string indent, GenBase type)
437437
} else {
438438
writer.WriteLine ("{0}// Metadata.xml XPath field reference: path=\"{1}/field[@name='{2}']\"", indent, type.MetadataXPathReference, field.JavaName);
439439
writer.WriteLine ("{0}[Register (\"{1}\"{2})]", indent, field.JavaName, field.AdditionalAttributeString ());
440-
if (field.IsDeprecated)
441-
writer.WriteLine ("{0}[Obsolete (\"{1}\")]", indent, field.DeprecatedComment);
440+
if (field.IsDeprecated) {
441+
var deprecatedError = field.IsDeprecatedError ? ", error: true" : string.Empty;
442+
writer.WriteLine ("{0}[Obsolete (\"{1}\"{2})]", indent, field.DeprecatedComment, deprecatedError);
443+
}
442444
if (field.Annotation != null)
443445
writer.WriteLine ("{0}{1}", indent, field.Annotation);
444446

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public static Field CreateField (XElement elem)
9595
DeprecatedComment = elem.XGetAttribute ("deprecated"),
9696
IsAcw = true,
9797
IsDeprecated = elem.XGetAttribute ("deprecated") != "not deprecated",
98+
IsDeprecatedError = elem.XGetAttribute ("deprecated-error") == "true",
9899
IsFinal = elem.XGetAttribute ("final") == "true",
99100
IsStatic = elem.XGetAttribute ("static") == "true",
100101
JavaName = elem.XGetAttribute ("name"),

tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class Field : ApiVersionsSupport.IApiAvailability
1111
public string DeprecatedComment { get; set; }
1212
public bool IsAcw { get; set; }
1313
public bool IsDeprecated { get; set; }
14+
public bool IsDeprecatedError { get; set; }
1415
public bool IsEnumified { get; set; }
1516
public bool IsFinal { get; set; }
1617
public bool IsStatic { get; set; }

tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ public EnumMappings (string outputDir, string outputMetadata, string version, bo
2424
fix_constants_instead_of_removing = fixConstantsInsteadOfRemove;
2525
}
2626

27-
internal Dictionary<string,EnumDescription> Process (string fieldMap, string flagsFile, string methodMap)
27+
internal Dictionary<string, EnumDescription> Process (string fieldMap, string flagsFile, string methodMap)
2828
{
29-
remove_nodes = new List<KeyValuePair<string,string>> ();
29+
remove_nodes = new List<KeyValuePair<string, string>> ();
3030
var enums = (fieldMap ?? "").EndsWith (".csv")
3131
? ParseFieldMappings (fieldMap, flagsFile, version, remove_nodes)
3232
: ParseXmlFieldMappings (fieldMap, version, remove_nodes);
@@ -48,12 +48,12 @@ internal Dictionary<string,EnumDescription> Process (string fieldMap, string fla
4848
FixOldConstants (sw);
4949
else
5050
RemoveOldConstants (sw);
51-
51+
5252
sw.WriteLine ("</metadata>");
5353
}
5454
return enums;
5555
}
56-
56+
5757
// <remove-node path="/api/package[@name='java.lang']/class[@name='Float']/field[@name='MAX_VALUE']" />
5858
void RemoveOldConstants (StreamWriter sw)
5959
{
@@ -81,14 +81,16 @@ void FixOldConstants (StreamWriter sw)
8181

8282
if (pair.Value != null) {
8383
sw.WriteLine (" <attr path=\"/api/package[@name='{0}']/{3}[@name='{1}']/field[@name='{2}']\" name=\"type\">{4}</attr>",
84-
package, type, member, enu.StartsWith ("I:") ? "interface" : "class", pair.Value);
84+
package, type, member, enu.StartsWith ("I:") ? "interface" : "class", pair.Value);
8585
sw.WriteLine (" <attr path=\"/api/package[@name='{0}']/{3}[@name='{1}']/field[@name='{2}']\" name=\"deprecated\">This constant will be removed in the future version. Use {4} enum directly instead of this field.</attr>",
86-
package, type, member, enu.StartsWith ("I:") ? "interface" : "class", pair.Value);
86+
package, type, member, enu.StartsWith ("I:") ? "interface" : "class", pair.Value);
87+
sw.WriteLine (" <attr path=\"/api/package[@name='{0}']/{3}[@name='{1}']/field[@name='{2}']\" name=\"deprecated-error\">true</attr>",
88+
package, type, member, enu.StartsWith ("I:") ? "interface" : "class", pair.Value);
8789
continue;
8890
}
8991
try {
9092
sw.WriteLine (" <remove-node path=\"/api/package[@name='{0}']/{3}[@name='{1}']/field[@name='{2}']\" />",
91-
package, type, member, enu.StartsWith ("I:") ? "interface" : "class");
93+
package, type, member, enu.StartsWith ("I:") ? "interface" : "class");
9294
} catch (Exception) {
9395
Console.Error.WriteLine ("ERROR: failed to remove old comments: " + enu);
9496
throw;

tools/generator/generator.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 2012
44
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator", "generator.csproj", "{D14A1B5C-2060-4930-92BE-F7190256C735}"
55
EndProject
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator-Tests", "Tests\generator-Tests.csproj", "{4EEAB1A7-99C1-4302-9C18-01A7B481409B}"
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator-Tests", "..\..\tests\generator-Tests\generator-Tests.csproj", "{4EEAB1A7-99C1-4302-9C18-01A7B481409B}"
77
EndProject
88
Global
99
GlobalSection(SolutionConfigurationPlatforms) = preSolution

0 commit comments

Comments
 (0)