diff --git a/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs b/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs index ab9346daf..6838e36c2 100644 --- a/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs +++ b/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs @@ -9,14 +9,14 @@ namespace Java.Interop.Tools.Generator.Enumification public class ConstantEntry { public ConstantAction Action { get; set; } - public int ApiLevel { get; set; } + public AndroidSdkVersion ApiLevel { get; set; } public string? JavaSignature { get; set; } public string? Value { get; set; } public string? EnumFullType { get; set; } public string? EnumMember { get; set; } public FieldAction FieldAction { get; set; } public bool IsFlags { get; set; } - public int? DeprecatedSince { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } public string EnumNamespace { get { @@ -100,7 +100,7 @@ static ConstantEntry FromVersion1String (CsvParser parser, bool transientMode) { var entry = new ConstantEntry { Action = ConstantAction.Enumify, - ApiLevel = parser.GetFieldAsInt (0), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (0), EnumFullType = parser.GetField (1), EnumMember = parser.GetField (2), JavaSignature = parser.GetField (3), @@ -128,14 +128,14 @@ static ConstantEntry FromVersion2String (CsvParser parser) { var entry = new ConstantEntry { Action = FromConstantActionString (parser.GetField (0)), - ApiLevel = parser.GetFieldAsInt (1), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (1), JavaSignature = parser.GetField (2), Value = parser.GetField (3), EnumFullType = parser.GetField (4), EnumMember = parser.GetField (5), FieldAction = FromFieldActionString (parser.GetField (6)), IsFlags = parser.GetField (7).ToLowerInvariant () == "flags", - DeprecatedSince = parser.GetFieldAsNullableInt32 (8) + DeprecatedSince = parser.GetFieldAsNullableAndroidSdkVersion (8) }; entry.NormalizeJavaSignature (); diff --git a/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs b/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs index 0d58e009a..52e26e3d7 100644 --- a/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs +++ b/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs @@ -8,7 +8,7 @@ namespace Java.Interop.Tools.Generator.Enumification public class MethodMapEntry { public MethodAction Action { get; set; } - public int ApiLevel { get; set; } + public AndroidSdkVersion ApiLevel { get; set; } public string? JavaPackage { get; set; } public string? JavaType { get; set; } public string? JavaName { get; set; } @@ -66,7 +66,7 @@ static MethodMapEntry FromVersion1String (CsvParser parser) { var entry = new MethodMapEntry { Action = MethodAction.Enumify, - ApiLevel = parser.GetFieldAsInt (0), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (0), JavaPackage = parser.GetField (1), JavaType = parser.GetField (2), JavaName = parser.GetField (3), @@ -86,7 +86,7 @@ static MethodMapEntry FromVersion2String (CsvParser parser) { var entry = new MethodMapEntry { Action = FromMethodActionString (parser.GetField (0)), - ApiLevel = parser.GetFieldAsInt (1), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (1), JavaPackage = parser.GetField (2), JavaType = parser.GetField (3), JavaName = parser.GetField (4), diff --git a/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs index 2c6c2b735..cf115d06f 100644 --- a/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs +++ b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs @@ -3,6 +3,8 @@ using System.Xml.Linq; using System.Xml.XPath; +using Java.Interop.Tools.Generator; + namespace Xamarin.Android.Tools { static class XmlExtensions @@ -13,11 +15,11 @@ static class XmlExtensions public static string? XGetAttribute (this XPathNavigator nav, string name, string ns) => nav.GetAttribute (name, ns)?.Trim (); - public static int? XGetAttributeAsInt (this XElement element, string name) + public static AndroidSdkVersion? XGetAttributeAsAndroidSdkVersion (this XElement element, string name) { var value = element.XGetAttribute (name); - if (int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) + if (AndroidSdkVersion.TryParse (value, out var result)) return result; return null; diff --git a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs index 65a97508a..3c169f9ae 100644 --- a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs +++ b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs @@ -28,7 +28,7 @@ public FixupXmlDocument (XDocument fixupDocument) public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int productVersion) { // Defaulting to 0 here is fine - int.TryParse (apiLevelString, out var apiLevel); + AndroidSdkVersion.TryParse (apiLevelString, out var apiLevel); var metadataChildren = FixupDocument.XPathSelectElements ("/metadata/*"); @@ -193,22 +193,22 @@ public IList GetNamespaceTransforms () return list; } - bool ShouldSkip (XElement node, int apiLevel, int productVersion) + bool ShouldSkip (XElement node, AndroidSdkVersion apiLevel, int productVersion) { if (apiLevel > 0) { - var since = node.XGetAttributeAsInt ("api-since"); - var until = node.XGetAttributeAsInt ("api-until"); + var since = node.XGetAttributeAsAndroidSdkVersion ("api-since"); + var until = node.XGetAttributeAsAndroidSdkVersion ("api-until"); - if (since is int since_int && since_int > apiLevel) + if (since is AndroidSdkVersion since_int && since_int > apiLevel) return true; - else if (until is int until_int && until_int < apiLevel) + else if (until is AndroidSdkVersion until_int && until_int < apiLevel) return true; } if (productVersion > 0) { - var product_version = node.XGetAttributeAsInt ("product-version"); + var product_version = node.XGetAttributeAsAndroidSdkVersion ("product-version"); - if (product_version is int version && version > productVersion) + if (product_version is AndroidSdkVersion version && version > productVersion) return true; } diff --git a/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs b/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs new file mode 100644 index 000000000..b78de05b6 --- /dev/null +++ b/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs @@ -0,0 +1,126 @@ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop.Tools.Generator; + +public struct AndroidSdkVersion : IComparable, IComparable, IEquatable +{ + public int ApiLevel { get; private set; } + public int MinorRelease { get; private set; } + + public AndroidSdkVersion (int major, int minor = 0) + { + ApiLevel = major; + MinorRelease = minor; + } + + int IComparable.CompareTo (object? value) + { + var other = value as AndroidSdkVersion?; + if (other == null) { + return 1; + } + return CompareTo (other.Value); + } + + public int CompareTo (AndroidSdkVersion value) + { + int r = ApiLevel.CompareTo (value.ApiLevel); + if (r == 0) { + r = MinorRelease.CompareTo (value.MinorRelease); + } + return r; + } + + public override int GetHashCode () + => ApiLevel ^ MinorRelease; + + public override bool Equals (object? value) + { + var other = value as AndroidSdkVersion?; + if (other == null) { + return false; + } + return Equals (other.Value); + } + + public bool Equals (AndroidSdkVersion value) + { + return value.ApiLevel == ApiLevel && value.MinorRelease == MinorRelease; + } + + public override string ToString () + => MinorRelease == 0 + ? ApiLevel.ToString () + : $"{ApiLevel}.{MinorRelease}"; + + // public static implicit operator ApiLevel (int value) + // => new ApiLevel (value); + + public static bool operator < (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) < 0; + public static bool operator <= (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) <= 0; + public static bool operator > (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) > 0; + public static bool operator >= (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) >= 0; + public static bool operator == (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.Equals (rhs); + public static bool operator != (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => !lhs.Equals (rhs); + + public static bool operator < (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) < 0; + public static bool operator <= (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) <= 0; + public static bool operator > (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) > 0; + public static bool operator >= (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) >= 0; + public static bool operator == (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.Equals (rhs); + public static bool operator != (AndroidSdkVersion lhs, int rhs) + => !lhs.ApiLevel.Equals (rhs); + + public static bool operator < (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) < 0; + public static bool operator <= (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) <= 0; + public static bool operator > (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) > 0; + public static bool operator >= (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) >= 0; + public static bool operator == (int lhs, AndroidSdkVersion rhs) + => lhs.Equals (rhs.ApiLevel); + public static bool operator != (int lhs, AndroidSdkVersion rhs) + => !lhs.Equals (rhs.ApiLevel); + + public static bool TryParse (string? value, out AndroidSdkVersion apiLevel) + { + if (value == null) { + apiLevel = default; + return false; + } + if (Version.TryParse (value, out var v)) { + apiLevel = new AndroidSdkVersion (v.Major, v.Minor); + return true; + } + if (int.TryParse (value, out var major)) { + apiLevel = new AndroidSdkVersion (major); + return true; + } + apiLevel = default; + return false; + } + + public static AndroidSdkVersion Parse (string? value) + { + AndroidSdkVersion v; + if (TryParse (value, out v)) { + return v; + } + throw new NotSupportedException ($"Could not parse `{value}` as an ApiLevel."); + } +} diff --git a/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs b/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs index 22e43a904..312281316 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs @@ -19,16 +19,16 @@ public string GetField (int index) return fields [index].Trim (); } - public int GetFieldAsInt (int index) + public AndroidSdkVersion GetFieldAsAndroidSdkVersion (int index) { - return int.Parse (GetField (index)); + return AndroidSdkVersion.Parse (GetField (index)); } - public int? GetFieldAsNullableInt32 (int index) + public AndroidSdkVersion? GetFieldAsNullableAndroidSdkVersion (int index) { var value = GetField (index); - if (int.TryParse (value, out var val)) + if (AndroidSdkVersion.TryParse (value, out var val)) return val; return default; diff --git a/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs b/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs index 0e17dbd8e..19c8d5ae2 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs @@ -9,26 +9,49 @@ public static class NamingConverter /// /// Converts a 'merge.SourceFile' attribute to an API level. (ex. "..\..\bin\BuildDebug\api\api-28.xml.in") /// - public static int ParseApiLevel (string? value) + public static AndroidSdkVersion ParseApiLevel (string? value) + { + var result = ExtractApiLevel (value); + if (!result.HasValue ()) + return default; + + return result switch { + "R" => new AndroidSdkVersion (30), + "S" => new AndroidSdkVersion (31), + _ => AndroidSdkVersion.Parse (result) + }; + } + + static string? ExtractApiLevel (string? value) { if (!value.HasValue ()) - return 0; + return null; - var hyphen = value.IndexOf ('-'); - var period = value.IndexOf ('.', hyphen); + var hyphen = value.IndexOf ('-'); + if (hyphen < 0 || (hyphen+1) >= value.Length) + return null; - var result = value.Substring (hyphen + 1, period - hyphen - 1); + int end = hyphen + 1; + if (char.IsAsciiDigit (value [end++])) { + for ( ; end < value.Length; ++end) { + var n = value [end + 1]; + if (!char.IsAsciiDigit (n) && n != '.') + break; + } + } else { + // codename; expect ALLCAPS + for ( ; end < value.Length; ++end) { + if (!char.IsAsciiLetterUpper (value [end])) + break; + } + } - return result switch { - "R" => 30, - "S" => 31, - _ => int.Parse (result) - }; + return value.Substring (hyphen + 1, end - hyphen - 1); } // The 'merge.SourceFile' attribute may be on the element, or only on its parent. For example, // a new 'class' added will only put the attribute on the '' element and not its children s. - public static int ParseApiLevel (XElement element) + public static AndroidSdkVersion ParseApiLevel (XElement element) { var loop = element; @@ -39,7 +62,7 @@ public static int ParseApiLevel (XElement element) loop = loop.Parent; } - return 0; + return default; } public static string ConvertNamespaceToCSharp (string v) diff --git a/src/utils/XmlExtensions.cs b/src/utils/XmlExtensions.cs index a72eb8f92..83fbc2ed7 100644 --- a/src/utils/XmlExtensions.cs +++ b/src/utils/XmlExtensions.cs @@ -5,6 +5,8 @@ using System.Xml.Linq; using System.Xml.XPath; +using Java.Interop.Tools.Generator; + namespace Xamarin.Android.Tools { static class XmlExtensions { @@ -21,14 +23,14 @@ public static string XGetAttribute (this XPathNavigator nav, string name, string return attr != null ? attr.Trim () : null; } - public static int? XGetAttributeAsIntOrNull (this XElement element, string name) + public static AndroidSdkVersion? XGetAttributeAsAndroidSdkVersionOrNull (this XElement element, string name) { var attr = element.Attribute (name); if (attr?.Value is null) return null; - if (int.TryParse (attr.Value, out var val)) + if (AndroidSdkVersion.TryParse (attr.Value, out var val)) return val; return null; diff --git a/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs b/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs index de2503567..49f544ecf 100644 --- a/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs +++ b/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs @@ -13,7 +13,7 @@ public void ParseEnumMapV1 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Enumify, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); @@ -29,7 +29,7 @@ public void ParseTransientEnumMapV1 () var entry = ConstantEntry.FromString (csv, true); Assert.AreEqual (ConstantAction.Enumify, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); @@ -45,7 +45,7 @@ public void ParseAddEnumMapV1 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Add, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual (string.Empty, entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); @@ -61,7 +61,7 @@ public void ParseRemoveEnumMapV1 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Remove, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual (string.Empty, entry.EnumFullType); @@ -77,7 +77,7 @@ public void ParseEnumMapV2 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Enumify, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); @@ -94,7 +94,7 @@ public void ParseAddEnumMapV2 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Add, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual (string.Empty, entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); @@ -111,14 +111,14 @@ public void ParseRemoveEnumMapV2 () var entry = ConstantEntry.FromString (csv); Assert.AreEqual (ConstantAction.Remove, entry.Action); - Assert.AreEqual (10, entry.ApiLevel); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); Assert.AreEqual ("5", entry.Value); Assert.AreEqual (string.Empty, entry.EnumFullType); Assert.AreEqual (string.Empty, entry.EnumMember); Assert.AreEqual (FieldAction.Remove, entry.FieldAction); Assert.False (entry.IsFlags); - Assert.AreEqual (33, entry.DeprecatedSince.Value); + Assert.AreEqual (33, entry.DeprecatedSince?.ApiLevel ?? 0); } } } diff --git a/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs b/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs new file mode 100644 index 000000000..dbe107168 --- /dev/null +++ b/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs @@ -0,0 +1,63 @@ +using System; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests; + +[TestFixture] +public class AndroidSdkVersionTests +{ + [Test] + public void CompareTo() + { + var a = new AndroidSdkVersion (1); + var b = new AndroidSdkVersion (1); + var c = new AndroidSdkVersion (36, 1); + Assert.AreEqual (0, a.CompareTo (b), $"1 == 1"); + Assert.AreEqual (1, ((IComparable)a).CompareTo (null), $"1 < null"); + Assert.IsTrue (a.CompareTo (c) < 0, $"1 < 36.1"); + Assert.IsTrue (c.CompareTo (a) > 0, $"36.1 > 1"); + } + + [Test] + public void Operators () + { + var a = new AndroidSdkVersion (1); + var b = new AndroidSdkVersion (1); + var c = new AndroidSdkVersion (36, 1); + + Assert.IsFalse (a < b); + Assert.IsTrue (a <= b); + Assert.IsTrue (a < c); + Assert.IsTrue (a <= c); + + Assert.IsFalse (a > b); + Assert.IsTrue (a >= b); + Assert.IsTrue (c > a); + Assert.IsTrue (c >= a); + } + + [Test] + public void TryParse () + { + AndroidSdkVersion v; + Assert.IsFalse (AndroidSdkVersion.TryParse (null, out v)); + Assert.IsFalse (AndroidSdkVersion.TryParse ("", out v)); + + Assert.IsTrue (AndroidSdkVersion.TryParse ("1", out v)); + Assert.AreEqual (1, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + + Assert.IsTrue (AndroidSdkVersion.TryParse ("36.1", out v)); + Assert.AreEqual (36, v.ApiLevel); + Assert.AreEqual (1, v.MinorRelease); + } + + [Test] + public new void ToString () + { + Assert.AreEqual ("0", new AndroidSdkVersion (0).ToString ()); + Assert.AreEqual ("36", new AndroidSdkVersion (36).ToString ()); + Assert.AreEqual ("36.1", new AndroidSdkVersion (36, 1).ToString ()); + } +} diff --git a/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs b/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs new file mode 100644 index 000000000..a825c7073 --- /dev/null +++ b/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs @@ -0,0 +1,33 @@ +using System; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests; + +[TestFixture] +public class NamingConverterTests +{ + [Test] + public void ParseApiLevel_Exceptions () + { + Assert.Throws (() => NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-CANARY.xml.in")); + } + + [Test] + public void ParseApiLevel () + { + AndroidSdkVersion v; + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-28.xml.in"); + Assert.AreEqual (28, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-36.1.xml.in"); + Assert.AreEqual (36, v.ApiLevel); + Assert.AreEqual (1, v.MinorRelease); + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-R.xml.in"); + Assert.AreEqual (30, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + } +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs index e1eb18fbe..c02b7def7 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs @@ -794,12 +794,12 @@ public void ObsoletedOSPlatformAttributeInterfaceInfrastructureSupport () // Ensure attribute was added to invoker class var invoker_attribute = invoker.Attributes.OfType ().Single (); Assert.AreEqual ("This interface was deprecated in API-25", invoker_attribute.Message); - Assert.AreEqual (25, invoker_attribute.Version); + Assert.AreEqual (25, invoker_attribute.Version.ApiLevel); // Ensure attribute was added to extensions class var extensions_attribute = invoker.Attributes.OfType ().Single (); Assert.AreEqual ("This interface was deprecated in API-25", extensions_attribute.Message); - Assert.AreEqual (25, extensions_attribute.Version); + Assert.AreEqual (25, extensions_attribute.Version.ApiLevel); } [Test] @@ -1223,7 +1223,7 @@ public void FixupDeprecatedSinceBaseMethods () var gens = ParseApiDefinition (xml); // Override method should match base method's 'deprecated-since' - Assert.AreEqual (11, gens.Single (g => g.Name == "MyClass").Methods.Single (m => m.Name == "DoStuff").DeprecatedSince); + Assert.AreEqual (11, gens.Single (g => g.Name == "MyClass").Methods.Single (m => m.Name == "DoStuff").DeprecatedSince?.ApiLevel ?? 0); } protected static IEnumerable GetLinesThatStartWith (string source, string value) @@ -1379,7 +1379,7 @@ public void SupportedOSPlatform () { // We do not write [SupportedOSPlatform] for JavaInterop, only XAJavaInterop var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); - klass.ApiAvailableSince = 30; + klass.ApiAvailableSince = new AndroidSdkVersion (30); generator.Context.ContextTypes.Push (klass); generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); @@ -1395,7 +1395,7 @@ public void SupportedOSPlatformConstFields () var klass = new TestClass ("java.lang.Object", "com.mypackage.foo"); var field = new TestField ("java.lang.String", "bar").SetConstant ("MY_VALUE"); - field.ApiAvailableSince = 30; + field.ApiAvailableSince = new AndroidSdkVersion (30); klass.Fields.Add (field); @@ -1410,7 +1410,7 @@ public void SupportedOSPlatformConstFields () public void UnsupportedOSPlatform () { var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); - klass.ApiRemovedSince = 30; + klass.ApiRemovedSince = new AndroidSdkVersion (30); generator.Context.ContextTypes.Push (klass); generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); @@ -1425,7 +1425,7 @@ public void UnsupportedOSPlatformConstFields () var klass = new TestClass ("java.lang.Object", "com.mypackage.foo"); var field = new TestField ("java.lang.String", "bar").SetConstant ("MY_VALUE"); - field.ApiRemovedSince = 30; + field.ApiRemovedSince = new AndroidSdkVersion (30); klass.Fields.Add (field); diff --git a/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs b/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs index 8d24860fe..f000b1497 100644 --- a/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs +++ b/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Text; +using Java.Interop.Tools.Generator; using Java.Interop.Tools.Generator.Enumification; using MonoDroid.Generation; using NUnit.Framework; @@ -150,7 +151,7 @@ public void ObsoletedOSPlatformAttributeOverrideSupport () options.UseObsoletedOSPlatformAttributes = true; var enu = CreateEnum (); - enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = 33; + enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = new AndroidSdkVersion (33); var gens = ParseApiDefinition (xml); @@ -177,7 +178,7 @@ public void ObsoleteAccidentalAddition () options.UseObsoletedOSPlatformAttributes = true; var enu = CreateEnum (); - enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = -1; + enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = new AndroidSdkVersion (-1); var gens = ParseApiDefinition (xml); @@ -198,7 +199,7 @@ public void ObsoleteAccidentalAddition () { var enu = new EnumMappings.EnumDescription { Members = new List { - new ConstantEntry { EnumMember = "WithExcluded", Value = "1", JavaSignature = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE", ApiLevel = 30 }, + new ConstantEntry { EnumMember = "WithExcluded", Value = "1", JavaSignature = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE", ApiLevel = new AndroidSdkVersion (30) }, new ConstantEntry { EnumMember = "IgnoreUnavailable", Value = "2", JavaSignature = "android/app/ActivityManager.RECENT_WITH_EXCLUDED" } }, BitField = false, diff --git a/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs b/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs index b624d1ad6..b8adbb59f 100644 --- a/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs +++ b/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs @@ -8,6 +8,8 @@ using MonoDroid.Generation; using NUnit.Framework; +using Java.Interop.Tools.Generator; + namespace generatortests { [TestFixture] @@ -22,7 +24,7 @@ public void BasicEnumificationTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); @@ -42,7 +44,7 @@ public void RemoveFieldOnlyTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); @@ -58,14 +60,14 @@ public void AddConstantOnlyTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual (0, removes.Count); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); Assert.AreEqual (false, enums.Single ().Value.BitField); Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved); - Assert.AreEqual ("", enums.First().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature); Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); } @@ -78,7 +80,7 @@ public void FlagsEnumerationTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual (true, enums.Single ().Value.BitField); } @@ -92,7 +94,7 @@ public void ExternalFlagsEnumerationTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, 30, removes); + var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, new AndroidSdkVersion (30), removes); Assert.AreEqual (true, enums.Single ().Value.BitField); } @@ -106,7 +108,7 @@ public void ApiVersionExcludedTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 5, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (5), removes); Assert.AreEqual (0, removes.Count); Assert.AreEqual (0, enums.Count); @@ -121,14 +123,14 @@ public void TransientEnumificationTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, Org.XmlPull.V1.XmlPullParserNode]", removes.Single ().ToString ()); Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); Assert.AreEqual (false, enums.Single ().Value.BitField); Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved); - Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature); Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); } @@ -141,7 +143,7 @@ public void TransientRemoveFieldOnlyTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); @@ -157,7 +159,7 @@ public void TransientAddConstantOnlyTest () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual (0, removes.Count); @@ -176,7 +178,7 @@ public void BasicEnumificationV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); @@ -196,7 +198,7 @@ public void RemoveFieldOnlyV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); @@ -212,7 +214,7 @@ public void AddConstantOnlyV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual (0, removes.Count); @@ -232,7 +234,7 @@ public void FlagsEnumerationV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual (true, enums.Single ().Value.BitField); } @@ -246,7 +248,7 @@ public void ExternalFlagsEnumerationV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, 30, removes); + var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, new AndroidSdkVersion (30), removes); Assert.AreEqual (true, enums.Single ().Value.BitField); } @@ -260,7 +262,7 @@ public void ApiVersionExcludedV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 5, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (5), removes); Assert.AreEqual (0, removes.Count); Assert.AreEqual (0, enums.Count); @@ -275,7 +277,7 @@ public void TransientEnumificationV2Test () var sr = new StringReader (csv); var removes = new List> (); - var enums = mappings.ParseFieldMappings (sr, new string [0], 30, removes); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, Org.XmlPull.V1.XmlPullParserNode]", removes.Single ().ToString ()); diff --git a/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs b/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs index b19aa96f5..472be69f4 100644 --- a/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs +++ b/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs @@ -28,7 +28,7 @@ public void CreateClass_CorrectApiSince () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.ApiAvailableSince); + Assert.AreEqual (7, klass.ApiAvailableSince.ApiLevel); } [Test] @@ -38,7 +38,7 @@ public void CreateClass_CorrectApiSinceFromPackage () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.ApiAvailableSince); + Assert.AreEqual (7, klass.ApiAvailableSince.ApiLevel); } [Test] @@ -48,7 +48,7 @@ public void CreateClass_CorrectApiSinceOverridePackage () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (9, klass.ApiAvailableSince); + Assert.AreEqual (9, klass.ApiAvailableSince.ApiLevel); } [Test] @@ -57,7 +57,7 @@ public void CreateClass_CorrectApiRemoved () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.ApiRemovedSince); + Assert.AreEqual (7, klass.ApiRemovedSince.ApiLevel); } [Test] @@ -75,7 +75,7 @@ public void CreateCtor_CorrectApiSince () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince); + Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince.ApiLevel); } [Test] @@ -84,7 +84,7 @@ public void CreateCtor_CorrectApiSinceFromClass () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince); + Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince.ApiLevel); } [Test] @@ -93,7 +93,7 @@ public void CreateCtor_CorrectDeprecatedSinceFromClass () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Ctors [0].DeprecatedSince); + Assert.AreEqual (7, klass.Ctors [0].DeprecatedSince.Value.ApiLevel); } [Test] @@ -143,17 +143,17 @@ public void CreateField_CorrectApiVersion () var xml = XDocument.Parse (""); var field = XmlApiImporter.CreateField (klass, xml.Root); - Assert.AreEqual (7, field.ApiAvailableSince); + Assert.AreEqual (7, field.ApiAvailableSince.ApiLevel); } [Test] public void CreateField_CorrectApiVersionFromClass () { - var klass = new TestClass ("object", "MyNamespace.MyType") { ApiAvailableSince = 7 }; + var klass = new TestClass ("object", "MyNamespace.MyType") { ApiAvailableSince = new AndroidSdkVersion (7) }; var xml = XDocument.Parse (""); var field = XmlApiImporter.CreateField (klass, xml.Root); - Assert.AreEqual (7, field.ApiAvailableSince); + Assert.AreEqual (7, field.ApiAvailableSince.ApiLevel); } [Test] @@ -162,7 +162,7 @@ public void CreateField_CorrectDeprecatedSinceFromClass () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Fields [0].DeprecatedSince); + Assert.AreEqual (7, klass.Fields [0].DeprecatedSince.Value.ApiLevel); } [Test] @@ -180,7 +180,7 @@ public void CreateInterface_CorrectApiSince () var xml = XDocument.Parse (""); var iface = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("interface"), opt); - Assert.AreEqual (7, iface.ApiAvailableSince); + Assert.AreEqual (7, iface.ApiAvailableSince.ApiLevel); } [Test] @@ -190,7 +190,7 @@ public void CreateInterface_CorrectApiSinceFromPackage () var xml = XDocument.Parse (""); var iface = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("interface"), opt); - Assert.AreEqual (7, iface.ApiAvailableSince); + Assert.AreEqual (7, iface.ApiAvailableSince.ApiLevel); } [Test] @@ -200,7 +200,7 @@ public void CreateInterface_CorrectApiSinceOverridePackage () var xml = XDocument.Parse (""); var iface = XmlApiImporter.CreateInterface (xml.Root, xml.Root.Element ("interface"), opt); - Assert.AreEqual (9, iface.ApiAvailableSince); + Assert.AreEqual (9, iface.ApiAvailableSince.ApiLevel); } [Test] @@ -227,7 +227,7 @@ public void CreateMethod_CorrectApiSince () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince); + Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince.ApiLevel); } [Test] @@ -236,7 +236,7 @@ public void CreateMethod_CorrectApiSinceFromClass () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince); + Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince.ApiLevel); } [Test] @@ -245,7 +245,7 @@ public void CreateMethod_CorrectDeprecatedSinceFromClass () var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); - Assert.AreEqual (7, klass.Methods [0].DeprecatedSince); + Assert.AreEqual (7, klass.Methods [0].DeprecatedSince.Value.ApiLevel); } [Test] diff --git a/tools/generator/ApiVersionsProvider.cs b/tools/generator/ApiVersionsProvider.cs index 487101482..3bd1c8fd7 100644 --- a/tools/generator/ApiVersionsProvider.cs +++ b/tools/generator/ApiVersionsProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Xml; using System.Linq; +using Java.Interop.Tools.Generator; namespace Xamarin.AndroidTools.AnnotationSupport { @@ -21,10 +22,10 @@ void Parse (XmlReader reader) reader.MoveToContent (); // -> class for (; reader.LocalName == "class"; reader.ReadToNextSibling ("class")) { - int tmpi; + AndroidSdkVersion tmpi; var name = reader.GetAttribute ("name").Replace ('/', '.').Replace ('$', '.'); - var since = int.Parse (reader.GetAttribute ("since")); - var deprecated = int.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : 0; + var since = AndroidSdkVersion.Parse (reader.GetAttribute ("since")); + var deprecated = AndroidSdkVersion.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : default; ClassDefinition klass; if (!Versions.TryGetValue (name, out klass)) { @@ -41,15 +42,15 @@ void Parse (XmlReader reader) var csince = reader.GetAttribute ("since"); if (csince == null) continue; - var cdeprecated = int.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : 0; + var cdeprecated = AndroidSdkVersion.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : default; var cname = reader.GetAttribute ("name"); switch (reader.LocalName) { case "field": - klass.Fields.Add (new Definition { Name = cname, Since = int.Parse (csince), Deprecated = cdeprecated }); + klass.Fields.Add (new Definition { Name = cname, Since = AndroidSdkVersion.Parse (csince), Deprecated = cdeprecated }); break; case "method": - klass.Methods.Add (new Definition { Name = cname, Since = int.Parse (csince), Deprecated = cdeprecated }); + klass.Methods.Add (new Definition { Name = cname, Since = AndroidSdkVersion.Parse (csince), Deprecated = cdeprecated }); break; } } @@ -59,8 +60,8 @@ void Parse (XmlReader reader) public class Definition { public string Name; // it is name + JNI signature for methods. - public int Since; - public int Deprecated; + public AndroidSdkVersion Since; + public AndroidSdkVersion Deprecated; string method; #if !GENERATOR diff --git a/tools/generator/ApiVersionsSupport.cs b/tools/generator/ApiVersionsSupport.cs index 524c7437d..d512a4027 100644 --- a/tools/generator/ApiVersionsSupport.cs +++ b/tools/generator/ApiVersionsSupport.cs @@ -3,13 +3,15 @@ using Xamarin.AndroidTools.AnnotationSupport; using System.Linq; +using Java.Interop.Tools.Generator; + namespace MonoDroid.Generation { static class IApiAvailabilityExtensions { public static string AdditionalAttributeString (this ApiVersionsSupport.IApiAvailability a) { - return a.ApiAvailableSince == 0 ? null : ", ApiSince = " + a.ApiAvailableSince; + return a.ApiAvailableSince.ApiLevel == 0 ? null : ", ApiSince = " + a.ApiAvailableSince.ApiLevel; } } @@ -17,8 +19,8 @@ public static class ApiVersionsSupport { public interface IApiAvailability { - int ApiAvailableSince { get; set; } - int ApiRemovedSince { get; set; } + AndroidSdkVersion ApiAvailableSince { get; set; } + AndroidSdkVersion ApiRemovedSince { get; set; } } static IEnumerable FlattenGens (IEnumerable gens) diff --git a/tools/generator/GenerationInfo.cs b/tools/generator/GenerationInfo.cs index 828802383..a10f3c9f1 100644 --- a/tools/generator/GenerationInfo.cs +++ b/tools/generator/GenerationInfo.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Xml.Linq; - +using Java.Interop.Tools.Generator; using Xamarin.Android.Binder; namespace MonoDroid.Generation { @@ -71,14 +71,23 @@ XElement ToDefineConstants (CodeGeneratorOptions options, XNamespace msbuild) { if (options.ApiLevel == null) return null; - int level; - if (!int.TryParse (options.ApiLevel, out level)) + AndroidSdkVersion level; + if (!AndroidSdkVersion.TryParse (options.ApiLevel, out level)) return null; var defines = new StringBuilder () .Append ("$(DefineConstants);ANDROID_1"); - for (int i = 2; i <= level; ++i) { + for (int i = 2; i <= level.ApiLevel; ++i) { defines.AppendFormat (";ANDROID_{0}", i.ToString ()); } + // ASSUME one minor release per major release starting with API-36.1 + for (int i = 36; i < level.ApiLevel; ++i) { + defines.Append ($";ANDROID_{i}_1"); + } + if (level.MinorRelease != 0) { + for (int i = 1; i < level.MinorRelease + 1; ++i) { + defines.Append ($";ANDROID_{level.ApiLevel}_{i}"); + } + } return new XElement ( msbuild + "PropertyGroup", new XElement ( diff --git a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs index 6c3a67767..5016f66be 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs @@ -162,7 +162,7 @@ public static Ctor CreateCtor (GenBase declaringType, XElement elem, CodeGenerat ApiRemovedSince = declaringType.ApiRemovedSince, CustomAttributes = elem.XGetAttribute ("customAttributes"), Deprecated = elem.Deprecated (), - DeprecatedSince = elem.XGetAttributeAsIntOrNull ("deprecated-since"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), GenericArguments = elem.GenericArguments (), Name = elem.XGetAttribute ("name"), Visibility = elem.Visibility () @@ -199,7 +199,7 @@ 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)) + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < ctor.DeprecatedSince.GetValueOrDefault (default)) ctor.DeprecatedSince = declaringType.DeprecatedSince; FillApiSince (ctor, elem); @@ -214,7 +214,7 @@ public static Field CreateField (GenBase declaringType, XElement elem, CodeGener ApiAvailableSince = declaringType.ApiAvailableSince, ApiRemovedSince = declaringType.ApiRemovedSince, DeprecatedComment = elem.XGetAttribute ("deprecated"), - DeprecatedSince = elem.XGetAttributeAsIntOrNull ("deprecated-since"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), IsAcw = true, IsDeprecated = elem.XGetAttribute ("deprecated") != "not deprecated", IsDeprecatedError = elem.XGetAttribute ("deprecated-error") == "true", @@ -244,7 +244,7 @@ public static Field CreateField (GenBase declaringType, XElement elem, CodeGener } // 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)) + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < field.DeprecatedSince.GetValueOrDefault (default)) field.DeprecatedSince = declaringType.DeprecatedSince; FillApiSince (field, elem); @@ -257,7 +257,7 @@ public static GenBaseSupport CreateGenBaseSupport (XElement pkg, XElement elem, { var support = new GenBaseSupport { AnnotatedVisibility = elem.XGetAttribute ("annotated-visibility"), - DeprecatedSince = elem.XGetAttributeAsIntOrNull ("deprecated-since"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), IsAcw = true, IsDeprecated = elem.XGetAttribute ("deprecated") != "not deprecated", IsGeneratable = true, @@ -375,7 +375,7 @@ public static Method CreateMethod (GenBase declaringType, XElement elem, CodeGen ArgsType = elem.Attribute ("argsType")?.Value, CustomAttributes = elem.XGetAttribute ("customAttributes"), Deprecated = elem.Deprecated (), - DeprecatedSince = elem.XGetAttributeAsIntOrNull ("deprecated-since"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), ExplicitInterface = elem.XGetAttribute ("explicitInterface"), EventName = elem.Attribute ("eventName")?.Value, GenerateAsyncWrapper = elem.Attribute ("generateAsyncWrapper") != null, @@ -428,7 +428,7 @@ 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)) + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < method.DeprecatedSince.GetValueOrDefault (default)) method.DeprecatedSince = declaringType.DeprecatedSince; FillApiSince (method, elem); @@ -519,9 +519,9 @@ static XElement GetPreviousClass (XNode n, string nameValue) static void FillApiSince (ApiVersionsSupport.IApiAvailability model, params XElement[] elems) { foreach (var elem in elems) { - if (int.TryParse (elem.XGetAttribute ("api-since"), out var result)) + if (AndroidSdkVersion.TryParse (elem.XGetAttribute ("api-since"), out var result)) model.ApiAvailableSince = result; - if (int.TryParse (elem.XGetAttribute ("removed-since"), out var removed)) + if (AndroidSdkVersion.TryParse (elem.XGetAttribute ("removed-since"), out var removed)) model.ApiRemovedSince = removed; } } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs index 4141993ee..1a3f89f5b 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs @@ -8,10 +8,10 @@ public class Field : ApiVersionsSupport.IApiAvailability, ISourceLineInfo { public string AnnotatedVisibility { get; set; } public string Annotation { get; set; } - public int ApiAvailableSince { get; set; } - public int ApiRemovedSince { get; set; } + public AndroidSdkVersion ApiAvailableSince { get; set; } + public AndroidSdkVersion ApiRemovedSince { get; set; } public string DeprecatedComment { get; set; } - public int? DeprecatedSince { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } public bool IsAcw { get; set; } public bool IsDeprecated { get; set; } public bool IsDeprecatedError { get; set; } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs index 6dfd897de..317835581 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs @@ -186,9 +186,9 @@ IEnumerable Ancestors () ? $"{FullName.Replace ('.', '/')}" : $"{Namespace}." + $"{FullName.Substring (Namespace.Length + 1).Replace ('.', '/')}"; - public int ApiAvailableSince { get; set; } + public AndroidSdkVersion ApiAvailableSince { get; set; } - public int ApiRemovedSince { get; set; } + public AndroidSdkVersion ApiRemovedSince { get; set; } public virtual ClassGen BaseGen => null; @@ -255,7 +255,7 @@ public bool ContainsProperty (string name, bool check_ifaces, bool check_base_if public string DeprecatedComment => support.DeprecatedComment; - public int? DeprecatedSince => support.DeprecatedSince; + public AndroidSdkVersion? DeprecatedSince => support.DeprecatedSince; IEnumerable Descendants (IList gens) { @@ -319,14 +319,14 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) m.Deprecated = bm.Deprecated; // Fix issue when base method was deprecated before the overriding method, set both both to base method value - if (bm.DeprecatedSince.GetValueOrDefault (0) < m.DeprecatedSince.GetValueOrDefault (0)) + if (bm.DeprecatedSince.GetValueOrDefault (default) < m.DeprecatedSince.GetValueOrDefault (default)) m.DeprecatedSince = bm.DeprecatedSince; } // If a "removed" method overrides a "not removed" method, the method was // likely moved to a base class, so don't mark it as removed. if (m.ApiRemovedSince > 0 && bm.ApiRemovedSince == 0) - m.ApiRemovedSince = 0; + m.ApiRemovedSince = default; break; } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs index 7aa011dad..027e5cf62 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Java.Interop.Tools.Generator; + namespace MonoDroid.Generation { public class GenBaseSupport @@ -11,7 +13,7 @@ public class GenBaseSupport public bool IsAcw { get; set; } public bool IsDeprecated { get; set; } public string DeprecatedComment { get; set; } - public int? DeprecatedSince { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } public bool IsGeneratable { get; set; } public bool IsGeneric { get; set; } public bool IsObfuscated { get; set; } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs index 4f548c729..2a8680faa 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs @@ -15,12 +15,12 @@ protected MethodBase (GenBase declaringType) public string AnnotatedVisibility { get; set; } public string Annotation { get; internal set; } - public int ApiAvailableSince { get; set; } - public int ApiRemovedSince { get; set; } + public AndroidSdkVersion ApiAvailableSince { get; set; } + public AndroidSdkVersion ApiRemovedSince { get; set; } public string AssemblyName { get; set; } public GenBase DeclaringType { get; } public string Deprecated { get; set; } - public int? DeprecatedSince { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } public GenericParameterDefinitionList GenericArguments { get; set; } public bool IsAcw { get; set; } public bool IsValid { get; private set; } diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs index 62902f8f8..589203799 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs @@ -14,14 +14,14 @@ partial class EnumMappings private string output_dir; private string output_metadata; private List> remove_nodes; - private int version; + private AndroidSdkVersion version; private bool fix_constants_instead_of_removing; public EnumMappings (string outputDir, string outputMetadata, string version, bool fixConstantsInsteadOfRemove) { output_dir = outputDir; output_metadata = outputMetadata; - this.version = version == null ? 0 : int.Parse (version); + this.version = version == null ? default : AndroidSdkVersion.Parse (version); fix_constants_instead_of_removing = fixConstantsInsteadOfRemove; } diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs index 66d0c487e..425fffb01 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs @@ -25,12 +25,12 @@ public class EnumDescription { public bool FieldsRemoved; } - internal Dictionary ParseXmlFieldMappings (string csv, int filter_version, IList> remove_nodes) + internal Dictionary ParseXmlFieldMappings (string csv, AndroidSdkVersion filter_version, IList> remove_nodes) { return ParseFieldMappings (FieldXmlToCsv (csv), null, filter_version, remove_nodes); } - internal Dictionary ParseFieldMappings (string csv, string flagsFile, int filter_version, IList> remove_nodes) + internal Dictionary ParseFieldMappings (string csv, string flagsFile, AndroidSdkVersion filter_version, IList> remove_nodes) { if (csv == null) return new Dictionary (); @@ -42,7 +42,7 @@ internal Dictionary ParseFieldMappings (string csv, str // value: Dictionary: // key: enum element name // value: enum element value - internal Dictionary ParseFieldMappings (TextReader source, string [] enumFlags, int filter_version, IList> remove_nodes) + internal Dictionary ParseFieldMappings (TextReader source, string [] enumFlags, AndroidSdkVersion filter_version, IList> remove_nodes) { var enums = new Dictionary (); @@ -184,12 +184,12 @@ StringReader MethodXmlToCsv (string file) return new StringReader (sw.ToString ()); } - internal List ParseXmlMethodMappings (string file, int filter_version) + internal List ParseXmlMethodMappings (string file, AndroidSdkVersion filter_version) { return ParseMethodMappings (MethodXmlToCsv (file), filter_version); } - internal List ParseMethodMappings (string file, int filter_version) + internal List ParseMethodMappings (string file, AndroidSdkVersion filter_version) { if (file == null) return new List (); @@ -197,7 +197,7 @@ internal List ParseMethodMappings (string file, int filter_version return ParseMethodMappings (sr, filter_version); } - internal List ParseMethodMappings (TextReader source, int filter_version) + internal List ParseMethodMappings (TextReader source, AndroidSdkVersion filter_version) { var list = new List (); if (source == null) @@ -213,8 +213,10 @@ internal List ParseMethodMappings (TextReader source, int filter_v if (s.Length == 0 || s.StartsWith ("//", StringComparison.Ordinal)) continue; var items = s.Split (','); - int ver; - if (filter_version > 0 && int.TryParse (items [0], out ver) && filter_version < ver) + AndroidSdkVersion ver; + if (filter_version > 0 && + AndroidSdkVersion.TryParse (items [0], out ver) && + filter_version < ver) continue; try { list.Add (new ApiTransform (preserveTypeMode, items)); diff --git a/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs b/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs index eecb0a87d..f8e398f4d 100644 --- a/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs +++ b/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs @@ -1,14 +1,16 @@ using System; using Xamarin.SourceWriter; +using Java.Interop.Tools.Generator; + namespace generator.SourceWriters { public class ObsoletedOSPlatformAttr : AttributeWriter { public string Message { get; set; } - public int Version { get; } + public AndroidSdkVersion Version { get; } - public ObsoletedOSPlatformAttr (string message, int version) + public ObsoletedOSPlatformAttr (string message, AndroidSdkVersion version) { Message = message; Version = version; @@ -16,10 +18,14 @@ public ObsoletedOSPlatformAttr (string message, int version) public override void WriteAttribute (CodeWriter writer) { + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + if (Message.HasValue ()) - writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{Version}.0\", @\"{Message.Replace ("\"", "\"\"")}\")]"); + writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{apiLevel}\", @\"{Message.Replace ("\"", "\"\"")}\")]"); else - writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{Version}.0\")]"); + writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{apiLevel}\")]"); } } } diff --git a/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs b/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs index f2f5021e2..6e79b48c8 100644 --- a/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs +++ b/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs @@ -5,17 +5,22 @@ using System.Threading.Tasks; using Xamarin.SourceWriter; +using Java.Interop.Tools.Generator; + namespace generator.SourceWriters { public class SupportedOSPlatformAttr : AttributeWriter { - public int Version { get; } + public AndroidSdkVersion Version { get; } - public SupportedOSPlatformAttr (int version) => Version = version; + public SupportedOSPlatformAttr (AndroidSdkVersion version) => Version = version; public override void WriteAttribute (CodeWriter writer) { - writer.WriteLine ($"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{Version}.0\")]"); + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + writer.WriteLine ($"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{apiLevel}\")]"); } } } diff --git a/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs b/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs index 27c789c4f..b15a70cbd 100644 --- a/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs +++ b/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs @@ -5,17 +5,22 @@ using System.Threading.Tasks; using Xamarin.SourceWriter; +using Java.Interop.Tools.Generator; + namespace generator.SourceWriters { public class UnsupportedOSPlatformAttr : AttributeWriter { - public int Version { get; } + public AndroidSdkVersion Version { get; } - public UnsupportedOSPlatformAttr (int version) => Version = version; + public UnsupportedOSPlatformAttr (AndroidSdkVersion version) => Version = version; public override void WriteAttribute (CodeWriter writer) { - writer.WriteLine ($"[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android{Version}.0\")]"); + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + writer.WriteLine ($"[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android{apiLevel}\")]"); } } } diff --git a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs index bbc1ca4f5..626eb1cb0 100644 --- a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs +++ b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs @@ -313,7 +313,7 @@ public static void AddSupportedOSPlatform (List attributes, Api AddUnsupportedOSPlatform (attributes, member.ApiRemovedSince, opt); } - public static void AddSupportedOSPlatform (List attributes, int since, CodeGenerationOptions opt) + public static void AddSupportedOSPlatform (List attributes, AndroidSdkVersion since, CodeGenerationOptions opt) { // There's no sense in writing say 'android15' because we do not support older APIs, // so those APIs will be available in all of our versions. @@ -321,14 +321,14 @@ public static void AddSupportedOSPlatform (List attributes, int attributes.Add (new SupportedOSPlatformAttr (since)); } - public static void AddUnsupportedOSPlatform (List attributes, int since, CodeGenerationOptions opt) + public static void AddUnsupportedOSPlatform (List attributes, AndroidSdkVersion since, CodeGenerationOptions opt) { // Here it makes sense to still write 'android15' because it will be missing in later versions like `android35`. if (since > 0 && opt.CodeGenerationTarget == CodeGenerationTarget.XAJavaInterop1) attributes.Add (new UnsupportedOSPlatformAttr (since)); } - public static void AddObsolete (List attributes, string message, CodeGenerationOptions opt, bool forceDeprecate = false, bool isError = false, int? deprecatedSince = null) + public static void AddObsolete (List attributes, string message, CodeGenerationOptions opt, bool forceDeprecate = false, bool isError = false, AndroidSdkVersion? deprecatedSince = null) { // Bail if we're not obsolete if ((!forceDeprecate && !message.HasValue ()) || message == "not deprecated") @@ -342,13 +342,13 @@ public static void AddObsolete (List attributes, string message } // Returns true if attribute was applied - static bool AddObsoletedOSPlatformAttribute (List attributes, string message, int? deprecatedSince, CodeGenerationOptions opt) + static bool AddObsoletedOSPlatformAttribute (List attributes, string message, AndroidSdkVersion? deprecatedSince, CodeGenerationOptions opt) { if (!opt.UseObsoletedOSPlatformAttributes) return false; // If it was obsoleted in a version earlier than we support (like 15), use a regular [Obsolete] instead - if (!deprecatedSince.HasValue || deprecatedSince <= MINIMUM_API_LEVEL) + if (!deprecatedSince.HasValue || deprecatedSince.Value <= MINIMUM_API_LEVEL) return false; // This is the default Android message, but it isn't useful so remove it diff --git a/tools/generator/Utilities/CsvParser.cs b/tools/generator/Utilities/CsvParser.cs index b2c5d134e..15e7b2648 100644 --- a/tools/generator/Utilities/CsvParser.cs +++ b/tools/generator/Utilities/CsvParser.cs @@ -22,10 +22,5 @@ public string GetField (int index) return fields [index].Trim (); } - - public int GetFieldAsInt (int index) - { - return int.Parse (GetField (index)); - } } }