diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs
index f8a550893..69d1b6455 100644
--- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs
+++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs
@@ -565,7 +565,8 @@ public void ObsoletedOSPlatformAttributeSupport ()
Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a field deprecated since 25!\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a constructor deprecated since 25!\")]"), writer.ToString ());
Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a method deprecated since 25!\")]"), writer.ToString ());
- Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a property getter deprecated since 25! This is a property setter deprecated since 25!\")]"), writer.ToString ());
+ Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a property getter deprecated since 25!\")]"), writer.ToString ());
+ Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a property setter deprecated since 25!\")]"), writer.ToString ());
}
[Test]
@@ -611,7 +612,152 @@ public void ObsoletedOSPlatformAttributeUnneededSupport ()
}
[Test]
- [NonParallelizable] // We are setting a static property on Report
+ public void ObsoleteGetterOnlyProperty ()
+ {
+ var xml = @"
+
+
+
+
+
+
+
+
+ ";
+
+ var gens = ParseApiDefinition (xml);
+ var iface = gens.Single (g => g.Name == "MyClass");
+
+ generator.Context.ContextTypes.Push (iface);
+ generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
+ generator.Context.ContextTypes.Pop ();
+
+ // This should use [Obsolete] on the entire property because the getter is obsolete and there is no setter
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete (@\"deprecated\")]public virtual unsafe int Count".NormalizeLineEndings ()), writer.ToString ());
+
+ // Ensure we don't write getter attribute
+ Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ());
+ }
+
+ [Test]
+ public void ObsoletePropertyGetter ()
+ {
+ var xml = @"
+
+
+
+
+
+
+
+
+
+
+
+ ";
+
+ var gens = ParseApiDefinition (xml);
+ var iface = gens.Single (g => g.Name == "MyClass");
+
+ generator.Context.ContextTypes.Push (iface);
+ generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
+ generator.Context.ContextTypes.Pop ();
+
+ // This should use [Obsolete] on just the property getter since the setter is not obsolete
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ());
+ }
+
+ [Test]
+ public void ObsoletePropertySetter ()
+ {
+ var xml = @"
+
+
+
+
+
+
+
+
+
+
+
+ ";
+
+ var gens = ParseApiDefinition (xml);
+ var iface = gens.Single (g => g.Name == "MyClass");
+
+ generator.Context.ContextTypes.Push (iface);
+ generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
+ generator.Context.ContextTypes.Pop ();
+
+ // This should use [Obsolete] on just the property setter since the getter is not obsolete
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]set"), writer.ToString ());
+ }
+
+ [Test]
+ public void ObsoleteBothPropertyMethods ()
+ {
+ var xml = @"
+
+
+
+
+
+
+
+
+
+
+
+ ";
+
+ var gens = ParseApiDefinition (xml);
+ var iface = gens.Single (g => g.Name == "MyClass");
+
+ generator.Context.ContextTypes.Push (iface);
+ generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
+ generator.Context.ContextTypes.Pop ();
+
+ // This should use [Obsolete] on both property methods because the deprecation messages are different
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"getter_message\")]get"), writer.ToString ());
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"setter_message\")]set"), writer.ToString ());
+ }
+
+ [Test]
+ public void ObsoleteEntireProperty ()
+ {
+ var xml = @"
+
+
+
+
+
+
+
+
+
+
+
+ ";
+
+ var gens = ParseApiDefinition (xml);
+ var iface = gens.Single (g => g.Name == "MyClass");
+
+ generator.Context.ContextTypes.Push (iface);
+ generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
+ generator.Context.ContextTypes.Pop ();
+
+ // This should use [Obsolete] on the entire property because the getter and setter are both obsoleted with the same message
+ Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete (@\"deprecated\")]public virtual unsafe int Count".NormalizeLineEndings ()), writer.ToString ());
+
+ // Ensure we don't write getter/setter attributes
+ Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ());
+ Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]set"), writer.ToString ());
+ }
+
+ [Test]
+ [NonParallelizable] // We are setting a static property on Report
public void WarnIfTypeNameMatchesNamespace ()
{
var @class = new TestClass ("Object", "java.myclass.MyClass");
@@ -650,6 +796,20 @@ public void DontWarnIfNestedTypeNameMatchesNamespace ()
// The warning should not be raised if the nested type matches enclosing namespace
Assert.False (sb.ToString ().Contains ("warning BG8403"));
}
+
+ static string StripRegisterAttributes (string str)
+ {
+ // It is hard to test if the [Obsolete] is on the setter/etc due to the [Register], so remove all [Register]s
+ // [global::System.Obsolete (@"setter_message")]
+ // [Register ("setCount", "(I)V", "GetSetCount_IHandler")]
+ // set {
+ int index;
+
+ while ((index = str.IndexOf ("[Register", StringComparison.Ordinal)) > -1)
+ str = str.Substring (0, index) + str.Substring (str.IndexOf (']', index) + 1);
+
+ return str;
+ }
}
[TestFixture]
diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs
index 57b4b59a8..a9a51ff74 100644
--- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs
+++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs
@@ -60,5 +60,32 @@ public void AutoDetectEnumifiedOverrideProperties (AncestorDescendantCache cache
}
public string ExplicitInterface => Getter?.ExplicitInterface ?? Setter?.ExplicitInterface;
+
+ public bool IsWholePropertyDeprecated {
+ get {
+ // If the getter isn't deprecated then the property isn't
+ if (Getter?.Deprecated is null)
+ return false;
+
+ // If the getter is deprecated and there is no setter then the property is deprecated
+ if (Setter is null)
+ return true;
+
+ // If the setter isn't deprecated then the property isn't
+ if (Setter.Deprecated is null)
+ return false;
+
+ // If the getter/setter deprecation messages differ, don't use whole property deprecation
+ if (Getter.Deprecated != Setter.Deprecated)
+ return false;
+
+ // If the getter/setter deprecation versions differ, don't use whole property deprecation
+ if (Getter.DeprecatedSince != Setter.DeprecatedSince)
+ return false;
+
+ // Getter/Setter deprecation is the same, use whole property deprecation
+ return true;
+ }
+ }
}
}
diff --git a/tools/generator/SourceWriters/BoundProperty.cs b/tools/generator/SourceWriters/BoundProperty.cs
index 240b86a95..591d37e91 100644
--- a/tools/generator/SourceWriters/BoundProperty.cs
+++ b/tools/generator/SourceWriters/BoundProperty.cs
@@ -72,11 +72,18 @@ public BoundProperty (GenBase gen, Property property, CodeGenerationOptions opt,
IsOverride = false;
}
- // Unlike [Register], [Obsolete] cannot be put on property accessors, so we can apply them only under limited condition...
- if (property.Getter.Deprecated != null && (property.Setter == null || property.Setter.Deprecated != null)) {
- var message = property.Getter.Deprecated.Trim () + (property.Setter != null && property.Setter.Deprecated != property.Getter.Deprecated ? " " + property.Setter.Deprecated.Trim () : null);
- var since = property.Getter?.DeprecatedSince ?? property.Setter?.DeprecatedSince;
- SourceWriterExtensions.AddObsolete (Attributes, message, opt, deprecatedSince: since);
+ // Add [Obsolete] or [ObsoletedOSPlatform]
+ if (property.IsWholePropertyDeprecated) {
+ // This case applies [Obsolete] to the entire property
+ SourceWriterExtensions.AddObsolete (Attributes, property.Getter.Deprecated.Trim (), opt, deprecatedSince: property.Getter.DeprecatedSince);
+ } else {
+ // This case applies [Obsolete] to just the getter
+ if (property.Getter?.Deprecated != null)
+ SourceWriterExtensions.AddObsolete (GetterAttributes, property.Getter.Deprecated.Trim (), opt, deprecatedSince: property.Getter?.DeprecatedSince);
+
+ // This case applies [Obsolete] to just the setter
+ if (property.Setter?.Deprecated != null)
+ SourceWriterExtensions.AddObsolete (SetterAttributes, property.Setter.Deprecated.Trim (), opt, deprecatedSince: property.Setter?.DeprecatedSince);
}
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt);