From 6ce1d94a090b76d29aec46f2b0eab09e16b66404 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 28 Jun 2020 12:59:53 +0200 Subject: [PATCH 1/3] Remove a few warnings. --- src/Avalonia.Base/PropertyStore/IPriorityValueEntry.cs | 7 +------ src/Avalonia.Styling/IStyledElement.cs | 5 ----- src/Avalonia.Styling/StyledElement.cs | 1 - src/Avalonia.Styling/Styling/Styles.cs | 1 - 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Avalonia.Base/PropertyStore/IPriorityValueEntry.cs b/src/Avalonia.Base/PropertyStore/IPriorityValueEntry.cs index 6ed6c2ef52..4d82381323 100644 --- a/src/Avalonia.Base/PropertyStore/IPriorityValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/IPriorityValueEntry.cs @@ -1,7 +1,4 @@ -using System; -using Avalonia.Data; - -#nullable enable +#nullable enable namespace Avalonia.PropertyStore { @@ -10,8 +7,6 @@ namespace Avalonia.PropertyStore /// internal interface IPriorityValueEntry : IValue { - BindingPriority Priority { get; } - void Reparent(IValueSink sink); } diff --git a/src/Avalonia.Styling/IStyledElement.cs b/src/Avalonia.Styling/IStyledElement.cs index 610c743a3e..37e6ed6fbb 100644 --- a/src/Avalonia.Styling/IStyledElement.cs +++ b/src/Avalonia.Styling/IStyledElement.cs @@ -17,11 +17,6 @@ namespace Avalonia /// event EventHandler Initialized; - /// - /// Raised when resources on the element are changed. - /// - event EventHandler ResourcesChanged; - /// /// Gets a value that indicates whether the element has finished initialization. /// diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index 05e031c9ec..65885ddebe 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -67,7 +67,6 @@ namespace Avalonia private List? _appliedStyles; private ITemplatedControl? _templatedParent; private bool _dataContextUpdating; - private bool _notifyingResourcesChanged; /// /// Initializes static members of the class. diff --git a/src/Avalonia.Styling/Styling/Styles.cs b/src/Avalonia.Styling/Styling/Styles.cs index 7c79060930..c752bdfeb8 100644 --- a/src/Avalonia.Styling/Styling/Styles.cs +++ b/src/Avalonia.Styling/Styling/Styles.cs @@ -21,7 +21,6 @@ namespace Avalonia.Styling private IResourceHost? _owner; private IResourceDictionary? _resources; private Dictionary?>? _cache; - private bool _notifyingResourcesChanged; public Styles() { From 128fbee51fc77b2b931be1cded41fd723921dc40 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 28 Jun 2020 13:51:34 +0200 Subject: [PATCH 2/3] Remove nullable and cref warnings. --- src/Avalonia.Base/AvaloniaProperty.cs | 4 +-- src/Avalonia.Base/AvaloniaPropertyRegistry.cs | 4 +-- .../Collections/Pooled/IReadOnlyPooledList.cs | 2 ++ .../Collections/Pooled/PooledList.cs | 3 +- src/Avalonia.Base/Data/BindingValue.cs | 36 +++++++++---------- src/Avalonia.Base/Data/Optional.cs | 10 +++--- src/Avalonia.Base/DirectPropertyBase.cs | 2 +- src/Avalonia.Base/IStyledPropertyMetadata.cs | 2 -- .../PropertyStore/LocalValueEntry.cs | 4 +-- src/Avalonia.Base/StyledPropertyMetadata`1.cs | 3 +- src/Avalonia.Base/ValueStore.cs | 2 +- 11 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index daa7191cc5..09480f2701 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -159,8 +159,6 @@ namespace Avalonia /// internal int Id { get; } - internal bool HasChangedSubscriptions => _changed?.HasObservers ?? false; - /// /// Provides access to a property's binding via the /// indexer. @@ -512,7 +510,7 @@ namespace Avalonia /// /// An if setting the property can be undone, otherwise null. /// - internal abstract IDisposable? RouteSetValue( + internal abstract IDisposable RouteSetValue( IAvaloniaObject o, object value, BindingPriority priority); diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs index 4a3b104f2a..4cde965400 100644 --- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs +++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs @@ -362,7 +362,7 @@ namespace Avalonia /// The property. /// /// You won't usually want to call this method directly, instead use the - /// + /// /// method. /// public void Register(Type type, AvaloniaProperty property) @@ -413,7 +413,7 @@ namespace Avalonia /// The property. /// /// You won't usually want to call this method directly, instead use the - /// + /// /// method. /// public void RegisterAttached(Type type, AvaloniaProperty property) diff --git a/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs b/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs index 9bc3609dc5..7a233a62ab 100644 --- a/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs +++ b/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs @@ -13,9 +13,11 @@ namespace Avalonia.Collections.Pooled public interface IReadOnlyPooledList : IReadOnlyList { +#pragma warning disable CS0419 /// /// Gets a for the items currently in the collection. /// +#pragma warning restore CS0419 ReadOnlySpan Span { get; } } } diff --git a/src/Avalonia.Base/Collections/Pooled/PooledList.cs b/src/Avalonia.Base/Collections/Pooled/PooledList.cs index f0d6b292cc..e50e100d32 100644 --- a/src/Avalonia.Base/Collections/Pooled/PooledList.cs +++ b/src/Avalonia.Base/Collections/Pooled/PooledList.cs @@ -138,7 +138,6 @@ namespace Avalonia.Collections.Pooled /// initially empty, but will have room for the given number of elements /// before any reallocations are required. /// - /// If true, Count of list equals capacity. Depending on ClearMode, rented items may or may not hold dirty values. public PooledList(int capacity, ClearMode clearMode, ArrayPool customPool, bool sizeToCapacity) { if (capacity < 0) @@ -499,11 +498,13 @@ namespace Avalonia.Collections.Pooled public void AddRange(T[] array) => AddRange(array.AsSpan()); +#pragma warning disable CS0419 /// /// Adds the elements of the given to the end of this list. If /// required, the capacity of the list is increased to twice the previous /// capacity or the new size, whichever is larger. /// +#pragma warning restore CS0419 public void AddRange(ReadOnlySpan span) { var newSpan = InsertSpan(_size, span.Length, false); diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 9aac1bacba..56f37ff89c 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -190,7 +190,7 @@ namespace Avalonia.Data /// Gets the value of the binding value if present, otherwise the default value. /// /// The value. - public T GetValueOrDefault() => HasValue ? _value : default; + public T GetValueOrDefault() => HasValue ? _value : default!; /// /// Gets the value of the binding value if present, otherwise a default value. @@ -209,8 +209,8 @@ namespace Avalonia.Data public TResult GetValueOrDefault() { return HasValue ? - _value is TResult result ? result : default - : default; + _value is TResult result ? result : default! + : default!; } /// @@ -225,7 +225,7 @@ namespace Avalonia.Data public TResult GetValueOrDefault(TResult defaultValue) { return HasValue ? - _value is TResult result ? result : default + _value is TResult result ? result : default! : defaultValue; } @@ -242,7 +242,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => (T)value + _ => (T)value! }; } @@ -259,18 +259,18 @@ namespace Avalonia.Data public static implicit operator BindingValue(Optional optional) { - return optional.HasValue ? optional.Value : Unset; + return optional.HasValue ? optional.Value! : Unset; } /// /// Returns a binding value with a type of . /// - public static BindingValue Unset => new BindingValue(BindingValueType.UnsetValue, default, null); + public static BindingValue Unset => new BindingValue(BindingValueType.UnsetValue, default!, null); /// /// Returns a binding value with a type of . /// - public static BindingValue DoNothing => new BindingValue(BindingValueType.DoNothing, default, null); + public static BindingValue DoNothing => new BindingValue(BindingValueType.DoNothing, default!, null); /// /// Returns a binding value with a type of . @@ -278,9 +278,9 @@ namespace Avalonia.Data /// The binding error. public static BindingValue BindingError(Exception e) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); - return new BindingValue(BindingValueType.BindingError, default, e); + return new BindingValue(BindingValueType.BindingError, default!, e); } /// @@ -290,7 +290,7 @@ namespace Avalonia.Data /// The fallback value. public static BindingValue BindingError(Exception e, T fallbackValue) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); return new BindingValue(BindingValueType.BindingErrorWithFallback, fallbackValue, e); } @@ -303,13 +303,13 @@ namespace Avalonia.Data /// The fallback value. public static BindingValue BindingError(Exception e, Optional fallbackValue) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); return new BindingValue( fallbackValue.HasValue ? BindingValueType.BindingErrorWithFallback : BindingValueType.BindingError, - fallbackValue.HasValue ? fallbackValue.Value : default, + fallbackValue.HasValue ? fallbackValue.Value : default!, e); } @@ -319,9 +319,9 @@ namespace Avalonia.Data /// The data validation error. public static BindingValue DataValidationError(Exception e) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); - return new BindingValue(BindingValueType.DataValidationError, default, e); + return new BindingValue(BindingValueType.DataValidationError, default!, e); } /// @@ -331,7 +331,7 @@ namespace Avalonia.Data /// The fallback value. public static BindingValue DataValidationError(Exception e, T fallbackValue) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); return new BindingValue(BindingValueType.DataValidationErrorWithFallback, fallbackValue, e); } @@ -344,13 +344,13 @@ namespace Avalonia.Data /// The fallback value. public static BindingValue DataValidationError(Exception e, Optional fallbackValue) { - e = e ?? throw new ArgumentNullException("e"); + e = e ?? throw new ArgumentNullException(nameof(e)); return new BindingValue( fallbackValue.HasValue ? BindingValueType.DataValidationErrorWithFallback : BindingValueType.DataValidationError, - fallbackValue.HasValue ? fallbackValue.Value : default, + fallbackValue.HasValue ? fallbackValue.Value : default!, e); } diff --git a/src/Avalonia.Base/Data/Optional.cs b/src/Avalonia.Base/Data/Optional.cs index dd952c895c..cc064e0faa 100644 --- a/src/Avalonia.Base/Data/Optional.cs +++ b/src/Avalonia.Base/Data/Optional.cs @@ -60,7 +60,7 @@ namespace Avalonia.Data /// Casts the value (if any) to an . /// /// The cast optional value. - public Optional ToObject() => HasValue ? new Optional(_value) : default; + public Optional ToObject() => HasValue ? new Optional(_value!) : default; /// public override string ToString() => HasValue ? _value?.ToString() ?? "(null)" : "(empty)"; @@ -69,7 +69,7 @@ namespace Avalonia.Data /// Gets the value if present, otherwise the default value. /// /// The value. - public T GetValueOrDefault() => HasValue ? _value : default; + public T GetValueOrDefault() => HasValue ? _value : default!; /// /// Gets the value if present, otherwise a default value. @@ -88,8 +88,8 @@ namespace Avalonia.Data public TResult GetValueOrDefault() { return HasValue ? - _value is TResult result ? result : default - : default; + _value is TResult result ? result : default! + : default!; } /// @@ -104,7 +104,7 @@ namespace Avalonia.Data public TResult GetValueOrDefault(TResult defaultValue) { return HasValue ? - _value is TResult result ? result : default + _value is TResult result ? result : default! : defaultValue; } diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index 0e65379abd..b59e86f8d5 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -122,7 +122,7 @@ namespace Avalonia internal override object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) { - return o.GetValue(this); + return o.GetValue(this)!; } /// diff --git a/src/Avalonia.Base/IStyledPropertyMetadata.cs b/src/Avalonia.Base/IStyledPropertyMetadata.cs index f567cd930c..a68b65e5e0 100644 --- a/src/Avalonia.Base/IStyledPropertyMetadata.cs +++ b/src/Avalonia.Base/IStyledPropertyMetadata.cs @@ -1,5 +1,3 @@ -using System; - namespace Avalonia { /// diff --git a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs index 59c017bc09..5d3930469d 100644 --- a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs @@ -15,11 +15,11 @@ namespace Avalonia.PropertyStore public LocalValueEntry(T value) => _value = value; public BindingPriority Priority => BindingPriority.LocalValue; - Optional IValue.GetValue() => new Optional(_value); + Optional IValue.GetValue() => new Optional(_value!); public Optional GetValue(BindingPriority maxPriority) { - return BindingPriority.LocalValue >= maxPriority ? _value : Optional.Empty; + return BindingPriority.LocalValue >= maxPriority ? _value! : Optional.Empty; } public void SetValue(T value) => _value = value; diff --git a/src/Avalonia.Base/StyledPropertyMetadata`1.cs b/src/Avalonia.Base/StyledPropertyMetadata`1.cs index 300548db0a..cf0a0c34ec 100644 --- a/src/Avalonia.Base/StyledPropertyMetadata`1.cs +++ b/src/Avalonia.Base/StyledPropertyMetadata`1.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using Avalonia.Data; namespace Avalonia @@ -35,7 +34,7 @@ namespace Avalonia /// /// Gets the value coercion callback, if any. /// - public Func? CoerceValue { get; private set; } + public Func CoerceValue { get; private set; } object IStyledPropertyMetadata.DefaultValue => DefaultValue; diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 05e66f2e0a..0e87a1f242 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -162,7 +162,7 @@ namespace Avalonia _sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( _owner, property, - old, + old!, default, BindingPriority.Unset)); } From de6553a0dc52917c84198f10f420ea903fe884ed Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 2 Jul 2020 11:15:56 +0200 Subject: [PATCH 3/3] Added nullable attributes and use them instead of `!`. --- src/Avalonia.Base/Data/BindingValue.cs | 44 +++--- src/Avalonia.Base/Data/Optional.cs | 26 ++-- src/Avalonia.Base/DirectPropertyBase.cs | 4 +- .../Metadata/NullableAttributes.cs | 140 ++++++++++++++++++ .../PropertyStore/LocalValueEntry.cs | 11 +- src/Avalonia.Base/ValueStore.cs | 2 +- 6 files changed, 188 insertions(+), 39 deletions(-) create mode 100644 src/Avalonia.Base/Metadata/NullableAttributes.cs diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 56f37ff89c..6e3c9ae67b 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Avalonia.Utilities; #nullable enable @@ -81,14 +82,14 @@ namespace Avalonia.Data /// public readonly struct BindingValue { - private readonly T _value; + [AllowNull] private readonly T _value; /// /// Initializes a new instance of the struct with a type of /// /// /// The value. - public BindingValue(T value) + public BindingValue([AllowNull] T value) { ValidateValue(value); _value = value; @@ -96,7 +97,7 @@ namespace Avalonia.Data Error = null; } - private BindingValue(BindingValueType type, T value, Exception? error) + private BindingValue(BindingValueType type, [AllowNull] T value, Exception? error) { _value = value; Type = type; @@ -154,7 +155,7 @@ namespace Avalonia.Data BindingValueType.UnsetValue => AvaloniaProperty.UnsetValue, BindingValueType.DoNothing => BindingOperations.DoNothing, BindingValueType.Value => _value, - BindingValueType.BindingError => + BindingValueType.BindingError => new BindingNotification(Error, BindingErrorType.Error), BindingValueType.BindingErrorWithFallback => new BindingNotification(Error, BindingErrorType.Error, Value), @@ -175,7 +176,7 @@ namespace Avalonia.Data /// The binding type is or /// . /// - public BindingValue WithValue(T value) + public BindingValue WithValue([AllowNull] T value) { if (Type == BindingValueType.DoNothing) { @@ -190,7 +191,8 @@ namespace Avalonia.Data /// Gets the value of the binding value if present, otherwise the default value. /// /// The value. - public T GetValueOrDefault() => HasValue ? _value : default!; + [return: MaybeNull] + public T GetValueOrDefault() => HasValue ? _value : default; /// /// Gets the value of the binding value if present, otherwise a default value. @@ -206,11 +208,12 @@ namespace Avalonia.Data /// The value if present and of the correct type, `default(TResult)` if the value is /// not present or of an incorrect type. /// + [return: MaybeNull] public TResult GetValueOrDefault() { return HasValue ? - _value is TResult result ? result : default! - : default!; + _value is TResult result ? result : default + : default; } /// @@ -222,10 +225,11 @@ namespace Avalonia.Data /// present but not of the correct type or null, or if the /// value is not present. /// - public TResult GetValueOrDefault(TResult defaultValue) + [return: MaybeNull] + public TResult GetValueOrDefault([AllowNull] TResult defaultValue) { return HasValue ? - _value is TResult result ? result : default! + _value is TResult result ? result : default : defaultValue; } @@ -242,7 +246,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => (T)value! + _ => new BindingValue((T)value) }; } @@ -250,7 +254,7 @@ namespace Avalonia.Data /// Creates a binding value from an instance of the underlying value type. /// /// The value. - public static implicit operator BindingValue(T value) => new BindingValue(value); + public static implicit operator BindingValue([AllowNull] T value) => new BindingValue(value); /// /// Creates a binding value from an . @@ -259,18 +263,18 @@ namespace Avalonia.Data public static implicit operator BindingValue(Optional optional) { - return optional.HasValue ? optional.Value! : Unset; + return optional.HasValue ? optional.Value : Unset; } /// /// Returns a binding value with a type of . /// - public static BindingValue Unset => new BindingValue(BindingValueType.UnsetValue, default!, null); + public static BindingValue Unset => new BindingValue(BindingValueType.UnsetValue, default, null); /// /// Returns a binding value with a type of . /// - public static BindingValue DoNothing => new BindingValue(BindingValueType.DoNothing, default!, null); + public static BindingValue DoNothing => new BindingValue(BindingValueType.DoNothing, default, null); /// /// Returns a binding value with a type of . @@ -280,7 +284,7 @@ namespace Avalonia.Data { e = e ?? throw new ArgumentNullException(nameof(e)); - return new BindingValue(BindingValueType.BindingError, default!, e); + return new BindingValue(BindingValueType.BindingError, default, e); } /// @@ -309,7 +313,7 @@ namespace Avalonia.Data fallbackValue.HasValue ? BindingValueType.BindingErrorWithFallback : BindingValueType.BindingError, - fallbackValue.HasValue ? fallbackValue.Value : default!, + fallbackValue.HasValue ? fallbackValue.Value : default, e); } @@ -321,7 +325,7 @@ namespace Avalonia.Data { e = e ?? throw new ArgumentNullException(nameof(e)); - return new BindingValue(BindingValueType.DataValidationError, default!, e); + return new BindingValue(BindingValueType.DataValidationError, default, e); } /// @@ -350,11 +354,11 @@ namespace Avalonia.Data fallbackValue.HasValue ? BindingValueType.DataValidationErrorWithFallback : BindingValueType.DataValidationError, - fallbackValue.HasValue ? fallbackValue.Value : default!, + fallbackValue.HasValue ? fallbackValue.Value : default, e); } - private static void ValidateValue(T value) + private static void ValidateValue([AllowNull] T value) { if (value is UnsetValueType) { diff --git a/src/Avalonia.Base/Data/Optional.cs b/src/Avalonia.Base/Data/Optional.cs index cc064e0faa..8e044d7896 100644 --- a/src/Avalonia.Base/Data/Optional.cs +++ b/src/Avalonia.Base/Data/Optional.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; #nullable enable @@ -22,13 +23,13 @@ namespace Avalonia.Data /// public readonly struct Optional : IEquatable> { - private readonly T _value; + [AllowNull] private readonly T _value; /// /// Initializes a new instance of the struct with value. /// /// The value. - public Optional(T value) + public Optional([AllowNull] T value) { _value = value; HasValue = true; @@ -48,7 +49,7 @@ namespace Avalonia.Data public T Value => HasValue ? _value : throw new InvalidOperationException("Optional has no value."); /// - public override bool Equals(object obj) => obj is Optional o && this == o; + public override bool Equals(object? obj) => obj is Optional o && this == o; /// public bool Equals(Optional other) => this == other; @@ -60,7 +61,7 @@ namespace Avalonia.Data /// Casts the value (if any) to an . /// /// The cast optional value. - public Optional ToObject() => HasValue ? new Optional(_value!) : default; + public Optional ToObject() => HasValue ? new Optional(_value) : default; /// public override string ToString() => HasValue ? _value?.ToString() ?? "(null)" : "(empty)"; @@ -69,7 +70,8 @@ namespace Avalonia.Data /// Gets the value if present, otherwise the default value. /// /// The value. - public T GetValueOrDefault() => HasValue ? _value : default!; + [return: MaybeNull] + public T GetValueOrDefault() => HasValue ? _value : default; /// /// Gets the value if present, otherwise a default value. @@ -85,11 +87,12 @@ namespace Avalonia.Data /// The value if present and of the correct type, `default(TResult)` if the value is /// not present or of an incorrect type. /// + [return: MaybeNull] public TResult GetValueOrDefault() { return HasValue ? - _value is TResult result ? result : default! - : default!; + _value is TResult result ? result : default + : default; } /// @@ -101,10 +104,11 @@ namespace Avalonia.Data /// present but not of the correct type or null, or if the /// value is not present. /// - public TResult GetValueOrDefault(TResult defaultValue) + [return: MaybeNull] + public TResult GetValueOrDefault([AllowNull] TResult defaultValue) { return HasValue ? - _value is TResult result ? result : default! + _value is TResult result ? result : default : defaultValue; } @@ -112,7 +116,7 @@ namespace Avalonia.Data /// Creates an from an instance of the underlying value type. /// /// The value. - public static implicit operator Optional(T value) => new Optional(value); + public static implicit operator Optional([AllowNull] T value) => new Optional(value); /// /// Compares two s for inequality. @@ -128,7 +132,7 @@ namespace Avalonia.Data /// The first value. /// The second value. /// True if the values are equal; otherwise false. - public static bool operator==(Optional x, Optional y) + public static bool operator ==(Optional x, Optional y) { if (!x.HasValue && !y.HasValue) { diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index b59e86f8d5..d42c030245 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -120,9 +120,9 @@ namespace Avalonia return o.GetValue(this); } - internal override object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) + internal override object? RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) { - return o.GetValue(this)!; + return o.GetValue(this); } /// diff --git a/src/Avalonia.Base/Metadata/NullableAttributes.cs b/src/Avalonia.Base/Metadata/NullableAttributes.cs new file mode 100644 index 0000000000..91f5e81863 --- /dev/null +++ b/src/Avalonia.Base/Metadata/NullableAttributes.cs @@ -0,0 +1,140 @@ +#pragma warning disable MA0048 // File name must match type name +#define INTERNAL_NULLABLE_ATTRIBUTES +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 + +// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class AllowNullAttribute : Attribute + { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DisallowNullAttribute : Attribute + { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullAttribute : Attribute + { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnAttribute : Attribute + { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +} +#endif diff --git a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs index 5d3930469d..859e9ba81c 100644 --- a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs @@ -1,4 +1,5 @@ -using Avalonia.Data; +using System.Diagnostics.CodeAnalysis; +using Avalonia.Data; #nullable enable @@ -11,15 +12,15 @@ namespace Avalonia.PropertyStore /// The property type. internal class LocalValueEntry : IValue { - private T _value; + [AllowNull] private T _value; - public LocalValueEntry(T value) => _value = value; + public LocalValueEntry([AllowNull] T value) => _value = value; public BindingPriority Priority => BindingPriority.LocalValue; - Optional IValue.GetValue() => new Optional(_value!); + Optional IValue.GetValue() => new Optional(_value); public Optional GetValue(BindingPriority maxPriority) { - return BindingPriority.LocalValue >= maxPriority ? _value! : Optional.Empty; + return BindingPriority.LocalValue >= maxPriority ? _value : Optional.Empty; } public void SetValue(T value) => _value = value; diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 0e87a1f242..6b89fcbdb9 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -162,7 +162,7 @@ namespace Avalonia _sink.ValueChanged(new AvaloniaPropertyChangedEventArgs( _owner, property, - old!, + new Optional(old), default, BindingPriority.Unset)); }