You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes: #1081
Context: dotnet/android-libraries#690
AndroidX has a [`@RestrictTo` annotation][0] that essentially means
"this API is implemented as `public`, but we do not consider it to be
supported API". (It can be considered as the equivalent of
[C# `internal` visibility][1] or of [.NET preview features][2].)
This means that Google reserves the right to change such types at any
time -- and they have! -- which can in turn break our apps.
Because we simply bound the API as `public`, it misled our users
into believing that this is a stable API they can rely on.
For example, consider dotnet/android-libraries#690, in which
[`androidx.appcompat.appcomat-resources`][3] "broke" API between
[version 1.5.1][4] and [version 1.6.0][5], because Google
[decided to promote classes][6] which had been
`@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})` in
version 1.5.1 to become "real" `public` types, and in the process
*renamed* those types, e.g. `DrawableWrapper` became
`DrawableWrapperCompat`. This renaming broke some of our customers.
Version 1.5.1:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class DrawableWrapper extends Drawable …
Version 1.6.0:

public class DrawableWrapperCompat extends Drawable …
The root problem is that we were binding `@RestrictTo` types which
never should have been bound. Fixing this involves two steps:
(1) detection, and (2) mitigation.
Update `class-parse` so that the `@RestrictTo` annotation is now
supported. If the `@RestrictTo` annotation is present, then a new
`//*/@annotated-visibility` attribute within `api.xml` will contain
the [`RestrictTo.Scope` values][7]
<class
name='DrawableWrapper'
…
annotated-visibility='LIBRARY_GROUP_PREFIX'
/>
Update `Xamarin.Android.Tools.ApiXmlAdjuster.dll` so that the new
`annotated-visibility` is supported and "passed through".
These changes allow `generator` to know that `@RestrictTo` was used
and what it was applied to, which brings us to mitigation:
We can't *not* continue binding these types; removing these types
would be an API break.
Instead, *for now*, we will add an `[Obsolete]` attribute to the
affected API with a message describing the situation:
[Obsolete (
"While this type is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.",
DiagnosticId = "XAOBS001")[]
public partial class DrawableWrapper {
}
This uses a custom warning code XAOBS001, which allows users to use
`$(NoWarn)` to ignore these warnings, if necessary.
Additionally, this new "`[Obsolete]` on `@RestrictTo` types" behavior
is *off by default*, and only enabled via the new
`generator --lang-features=restrict-to-attributes` option.
Note that only one `[Obsolete]` is allowed on each type/member, so if
the API already has an `[Obsolete]` attribute, e.g. because it is
`@Deprecated`, then the XAOBS001 obsolete message will be skipped.
TODO: Enable `generator --lang-features=restrict-to-attributes` in
.NET Android Binding Projects, with an MSBuild property to disable
this option if necessary.
TODO: *Eventually* we'll also need a way to *not* bind these types.
[0]: https://developer.android.com/reference/androidx/annotation/RestrictTo
[1]: https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/internal
[2]: https://github.com/dotnet/designs/blob/7d0be161bfb55117543f2833b645e089b646f8ab/accepted/2021/preview-features/preview-features.md
[3]: https://maven.google.com/web/index.html?q=androidx.appcompat#androidx.appcompat:appcompat-resources
[4]: https://dl.google.com/android/maven2/androidx/appcompat/appcompat-resources/1.5.1/appcompat-resources-1.5.1.aar
[5]: https://dl.google.com/android/maven2/androidx/appcompat/appcompat-resources/1.6.0/appcompat-resources-1.6.0.aar
[6]: https://android-review.googlesource.com/c/platform/frameworks/support/+/2120177
[7]: https://developer.android.com/reference/androidx/annotation/RestrictTo.Scope
// This should use a special [Obsolete] describing the "internal" nature of this API
917
+
Assert.True(writer.ToString().NormalizeLineEndings().Contains("[global::System.Obsolete (\"While this type is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings()),writer.ToString());
// This should use a special [Obsolete] describing the "internal" nature of this API
944
+
Assert.True(writer.ToString().NormalizeLineEndings().Contains("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings()),writer.ToString());
// This should use a special [Obsolete] describing the "internal" nature of this API
971
+
Assert.True(writer.ToString().NormalizeLineEndings().Contains("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings()),writer.ToString());
// This should use a special [Obsolete] describing the "internal" nature of this API
1001
+
Assert.True(writer.ToString().NormalizeLineEndings().Contains("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings()),writer.ToString());
Assert.False(writer.ToString().NormalizeLineEndings().Contains("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings()),writer.ToString());
1031
+
}
1032
+
895
1033
[Test]
896
1034
[NonParallelizable]// We are setting a static property on Report
0 commit comments