Browse Source

Merge pull request #11192 from AvaloniaUI/add-message-arg-to-the-unstable-attr

Add message to the Unstable attribute
Nikita Tsukanov 2 years ago
parent
commit
0495f10174

+ 15 - 9
nukebuild/RefAssemblyGenerator.cs

@@ -96,7 +96,7 @@ public class RefAssemblyGenerator
                     | 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 @@ public class RefAssemblyGenerator
         }
     }
 
-    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 class RefAssemblyGenerator
                 }
         }
     }
-}
+}

+ 1 - 2
src/Avalonia.Base/Controls/IThemeVariantProvider.cs

@@ -10,9 +10,8 @@ namespace Avalonia.Controls;
 /// <remarks>
 /// 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.
 /// </remarks>
-[Unstable]
+[Unstable("This XAML-only API might be removed in the future minor updates.")]
 public interface IThemeVariantProvider : IResourceProvider
 {
     /// <summary>

+ 1 - 2
src/Avalonia.Base/Input/DragEventArgs.cs

@@ -25,8 +25,7 @@ namespace Avalonia.Input
             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<DragEventArgs> routedEvent, IDataObject data, Interactive target, Point targetLocation, KeyModifiers keyModifiers)
             : base(routedEvent)
         {

+ 1 - 2
src/Avalonia.Base/Input/PointerDeltaEventArgs.cs

@@ -9,8 +9,7 @@ namespace Avalonia.Input
     {
         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) 

+ 4 - 8
src/Avalonia.Base/Input/PointerEventArgs.cs

@@ -14,8 +14,7 @@ namespace Avalonia.Input
         private readonly PointerPointProperties _properties;
         private readonly Lazy<IReadOnlyList<RawPointerPoint>?>? _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 @@ namespace Avalonia.Input
 
     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 @@ namespace Avalonia.Input
 
     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 @@ namespace Avalonia.Input
     {
         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;

+ 1 - 2
src/Avalonia.Base/Input/PointerWheelEventArgs.cs

@@ -9,8 +9,7 @@ namespace Avalonia.Input
     {
         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)

+ 21 - 1
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
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UnstableAttribute"/> class.
+        /// </summary>
+        public UnstableAttribute()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UnstableAttribute"/> class.
+        /// </summary>
+        /// <param name="message">The text string that describes alternative workarounds.</param>
+        public UnstableAttribute(string? message)
+        {
+            Message = message;
+        }
+
+        /// <summary>
+        /// Gets a value that indicates whether the compiler will treat usage of the obsolete program element as an error.
+        /// </summary>
+        public string? Message { get; }
     }
 }

+ 1 - 1
src/Avalonia.Base/Platform/IAssetLoader.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Platform
     /// <summary>
     /// Loads assets compiled into the application binary.
     /// </summary>
-    [Unstable]
+    [Unstable("IAssetLoader interface and AvaloniaLocator usage is considered unstable. Please use AssetLoader static class instead.")]
     public interface IAssetLoader
     {
         /// <summary>