From a11bef715b283b99adb535dfa857e039573bce1f Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sat, 29 Apr 2023 23:44:21 -0400 Subject: [PATCH 1/2] Add Message parameter to the Unstable attribute --- nukebuild/RefAssemblyGenerator.cs | 24 ++++++++++++------- .../Metadata/UnstableAttribute.cs | 22 ++++++++++++++++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/nukebuild/RefAssemblyGenerator.cs b/nukebuild/RefAssemblyGenerator.cs index cbe5236bca4..f0d5c81a379 100644 --- a/nukebuild/RefAssemblyGenerator.cs +++ b/nukebuild/RefAssemblyGenerator.cs @@ -96,7 +96,7 @@ static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor) | MethodAttributes.HideBySig, type.Module.TypeSystem.Void)); } - var forceUnstable = type.CustomAttributes.Any(a => + var forceUnstable = type.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute"); foreach (var m in type.Methods) @@ -109,22 +109,28 @@ static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor) } } - static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force) + static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute) { - if (!force && ( - def.HasCustomAttributes == false - || def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute"))) + if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute")) return; - if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute")) + unstableAttribute = def.CustomAttributes.FirstOrDefault(a => + a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute") ?? unstableAttribute; + + if (unstableAttribute is null) return; + var message = unstableAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString(); + if (string.IsNullOrEmpty(message)) + { + message = "This is a part of unstable API and can be changed in minor releases. Consider replacing it with alternatives or reach out developers on GitHub."; + } + def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor) { ConstructorArguments = { - new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String, - "This is a part of unstable API and can be changed in minor releases. You have been warned") + new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String, message) } }); } @@ -168,4 +174,4 @@ public static void GenerateRefAsmsInPackage(string packagePath) } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Metadata/UnstableAttribute.cs b/src/Avalonia.Base/Metadata/UnstableAttribute.cs index 361f6d30fd4..bbb298f7a60 100644 --- a/src/Avalonia.Base/Metadata/UnstableAttribute.cs +++ b/src/Avalonia.Base/Metadata/UnstableAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Avalonia.Metadata { @@ -9,5 +9,25 @@ namespace Avalonia.Metadata [AttributeUsage(AttributeTargets.All)] public sealed class UnstableAttribute : Attribute { + /// + /// Initializes a new instance of the class. + /// + public UnstableAttribute() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The text string that describes alternative workarounds. + public UnstableAttribute(string? message) + { + Message = message; + } + + /// + /// Gets a value that indicates whether the compiler will treat usage of the obsolete program element as an error. + /// + public string? Message { get; } } } From bbeef11aeddf8283efeb4bbdb7873f5863d29e56 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sat, 29 Apr 2023 23:44:49 -0400 Subject: [PATCH 2/2] Adjust some Unstable attr usages --- src/Avalonia.Base/Controls/IThemeVariantProvider.cs | 3 +-- src/Avalonia.Base/Input/DragEventArgs.cs | 3 +-- src/Avalonia.Base/Input/PointerDeltaEventArgs.cs | 3 +-- src/Avalonia.Base/Input/PointerEventArgs.cs | 12 ++++-------- src/Avalonia.Base/Input/PointerWheelEventArgs.cs | 3 +-- src/Avalonia.Base/Platform/IAssetLoader.cs | 2 +- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Base/Controls/IThemeVariantProvider.cs b/src/Avalonia.Base/Controls/IThemeVariantProvider.cs index d1dca2efbfd..03a7fb1206f 100644 --- a/src/Avalonia.Base/Controls/IThemeVariantProvider.cs +++ b/src/Avalonia.Base/Controls/IThemeVariantProvider.cs @@ -10,9 +10,8 @@ namespace Avalonia.Controls; /// /// This is a helper interface for the XAML compiler to make Key property accessibly by the markup extensions. /// Which means, it can only be used with ResourceDictionaries and markup extensions in the XAML code. -/// This API might be removed in the future minor updates. /// -[Unstable] +[Unstable("This XAML-only API might be removed in the future minor updates.")] public interface IThemeVariantProvider : IResourceProvider { /// diff --git a/src/Avalonia.Base/Input/DragEventArgs.cs b/src/Avalonia.Base/Input/DragEventArgs.cs index 8d7cc2b9a1f..26ec98361bc 100644 --- a/src/Avalonia.Base/Input/DragEventArgs.cs +++ b/src/Avalonia.Base/Input/DragEventArgs.cs @@ -25,8 +25,7 @@ public Point GetPosition(Visual relativeTo) return _target.TranslatePoint(_targetLocation, relativeTo) ?? new Point(0, 0); } - [Unstable] - [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using DragDrop.DoDragDrop or IHeadlessWindow.DragDrop.")] + [Unstable("This constructor might be removed in 12.0. For unit testing, consider using DragDrop.DoDragDrop or IHeadlessWindow.DragDrop.")] public DragEventArgs(RoutedEvent routedEvent, IDataObject data, Interactive target, Point targetLocation, KeyModifiers keyModifiers) : base(routedEvent) { diff --git a/src/Avalonia.Base/Input/PointerDeltaEventArgs.cs b/src/Avalonia.Base/Input/PointerDeltaEventArgs.cs index c405cdfacdb..3c4562edf49 100644 --- a/src/Avalonia.Base/Input/PointerDeltaEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerDeltaEventArgs.cs @@ -9,8 +9,7 @@ public class PointerDeltaEventArgs : PointerEventArgs { public Vector Delta { get; } - [Unstable] - [Obsolete("This constructor might be removed in 12.0.")] + [Unstable("This constructor might be removed in 12.0.")] public PointerDeltaEventArgs(RoutedEvent routedEvent, object? source, IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, KeyModifiers modifiers, Vector delta) diff --git a/src/Avalonia.Base/Input/PointerEventArgs.cs b/src/Avalonia.Base/Input/PointerEventArgs.cs index beb953ce8f9..7f82199b561 100644 --- a/src/Avalonia.Base/Input/PointerEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerEventArgs.cs @@ -14,8 +14,7 @@ public class PointerEventArgs : RoutedEventArgs private readonly PointerPointProperties _properties; private readonly Lazy?>? _previousPoints; - [Unstable] - [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] + [Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] public PointerEventArgs(RoutedEvent routedEvent, object? source, IPointer pointer, @@ -129,8 +128,7 @@ public enum MouseButton public class PointerPressedEventArgs : PointerEventArgs { - [Unstable] - [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] + [Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] public PointerPressedEventArgs( object source, IPointer pointer, @@ -150,8 +148,7 @@ public PointerPressedEventArgs( public class PointerReleasedEventArgs : PointerEventArgs { - [Unstable] - [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] + [Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")] public PointerReleasedEventArgs( object source, IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp, @@ -173,8 +170,7 @@ public class PointerCaptureLostEventArgs : RoutedEventArgs { public IPointer Pointer { get; } - [Unstable] - [Obsolete("This constructor might be removed in 12.0. If you need to remove capture, use stable methods on the IPointer instance.,")] + [Unstable("This constructor might be removed in 12.0. If you need to remove capture, use stable methods on the IPointer instance.,")] public PointerCaptureLostEventArgs(object source, IPointer pointer) : base(InputElement.PointerCaptureLostEvent) { Pointer = pointer; diff --git a/src/Avalonia.Base/Input/PointerWheelEventArgs.cs b/src/Avalonia.Base/Input/PointerWheelEventArgs.cs index 903019d85df..22624a61dd4 100644 --- a/src/Avalonia.Base/Input/PointerWheelEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerWheelEventArgs.cs @@ -9,8 +9,7 @@ public class PointerWheelEventArgs : PointerEventArgs { public Vector Delta { get; } - [Unstable] - [Obsolete("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow.MouseWheel.")] + [Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow.MouseWheel.")] public PointerWheelEventArgs(object source, IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, KeyModifiers modifiers, Vector delta) diff --git a/src/Avalonia.Base/Platform/IAssetLoader.cs b/src/Avalonia.Base/Platform/IAssetLoader.cs index b65d61803f1..f1ce624c706 100644 --- a/src/Avalonia.Base/Platform/IAssetLoader.cs +++ b/src/Avalonia.Base/Platform/IAssetLoader.cs @@ -9,7 +9,7 @@ namespace Avalonia.Platform /// /// Loads assets compiled into the application binary. /// - [Unstable] + [Unstable("IAssetLoader interface and AvaloniaLocator usage is considered unstable. Please use AssetLoader static class instead.")] public interface IAssetLoader { ///