From 15a406296c9bd06a51fd47d78a82dc2671d7642c Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 6 Dec 2021 20:57:27 -0500 Subject: [PATCH] Merge pull request #7082 from AvaloniaUI/fixes/avalonia-collections-nullability Add nullable annotations to Avalonia.Collections. --- .../Collections/AvaloniaDictionary.cs | 6 +- src/Avalonia.Base/Collections/AvaloniaList.cs | 61 +++++++++-------- .../Collections/AvaloniaListConverter.cs | 2 + .../Collections/AvaloniaListExtensions.cs | 4 +- .../Collections/IAvaloniaList.cs | 2 + .../Collections/IAvaloniaReadOnlyList.cs | 2 + .../NotifyCollectionChangedExtensions.cs | 12 ++-- .../Collections/Pooled/ClearMode.cs | 2 + .../Pooled/ICollectionDebugView.cs | 2 + .../Collections/Pooled/IReadOnlyPooledList.cs | 2 + .../Collections/Pooled/PooledList.cs | 49 +++++++------- .../Collections/Pooled/PooledStack.cs | 22 ++++--- .../Collections/Pooled/StackDebugView.cs | 2 + .../Collections/Pooled/ThrowHelper.cs | 66 ++++++++++++++++--- .../Controls/ResourceDictionary.cs | 3 +- 15 files changed, 155 insertions(+), 82 deletions(-) diff --git a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs index a3c51dc965..e5ee1e1eef 100644 --- a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs +++ b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs @@ -6,6 +6,8 @@ using System.ComponentModel; using System.Linq; using Avalonia.Data.Core; +#nullable enable + namespace Avalonia.Collections { /// @@ -31,12 +33,12 @@ namespace Avalonia.Collections /// /// Occurs when the collection changes. /// - public event NotifyCollectionChangedEventHandler CollectionChanged; + public event NotifyCollectionChangedEventHandler? CollectionChanged; /// /// Raised when a property on the collection changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; /// public int Count => _inner.Count; diff --git a/src/Avalonia.Base/Collections/AvaloniaList.cs b/src/Avalonia.Base/Collections/AvaloniaList.cs index 2f1cb2888e..b95f8f6bb6 100644 --- a/src/Avalonia.Base/Collections/AvaloniaList.cs +++ b/src/Avalonia.Base/Collections/AvaloniaList.cs @@ -6,6 +6,8 @@ using System.ComponentModel; using System.Linq; using Avalonia.Diagnostics; +#nullable enable + namespace Avalonia.Collections { /// @@ -53,7 +55,7 @@ namespace Avalonia.Collections public class AvaloniaList : IAvaloniaList, IList, INotifyCollectionChangedDebug { private readonly List _inner; - private NotifyCollectionChangedEventHandler _collectionChanged; + private NotifyCollectionChangedEventHandler? _collectionChanged; /// /// Initializes a new instance of the class. @@ -102,7 +104,7 @@ namespace Avalonia.Collections /// /// Raised when a property on the collection changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; /// /// Gets the number of items in the collection. @@ -118,7 +120,7 @@ namespace Avalonia.Collections /// Gets or sets a validation routine that can be used to validate items before they are /// added. /// - public Action Validate { get; set; } + public Action? Validate { get; set; } /// bool IList.IsFixedSize => false; @@ -133,7 +135,7 @@ namespace Avalonia.Collections bool ICollection.IsSynchronized => false; /// - object ICollection.SyncRoot => null; + object? ICollection.SyncRoot => null; /// bool ICollection.IsReadOnly => false; @@ -178,10 +180,10 @@ namespace Avalonia.Collections /// /// The index. /// The item. - object IList.this[int index] + object? IList.this[int index] { get { return this[index]; } - set { this[index] = (T)value; } + set { this[index] = (T)value!; } } /// @@ -318,7 +320,7 @@ namespace Avalonia.Collections /// The items. public virtual void InsertRange(int index, IEnumerable items) { - Contract.Requires(items != null); + _ = items ?? throw new ArgumentNullException(nameof(items)); bool willRaiseCollectionChanged = _collectionChanged != null; bool hasValidation = Validate != null; @@ -333,7 +335,7 @@ namespace Avalonia.Collections { foreach (T item in collection) { - Validate(item); + Validate!(item); } } @@ -354,7 +356,7 @@ namespace Avalonia.Collections if (hasValidation) { - Validate(item); + Validate!(item); } _inner.Insert(insertIndex++, item); @@ -372,7 +374,7 @@ namespace Avalonia.Collections if (en.MoveNext()) { // Avoid allocating list for collection notification if there is no event subscriptions. - List notificationItems = willRaiseCollectionChanged ? + List? notificationItems = willRaiseCollectionChanged ? new List() : null; @@ -384,19 +386,17 @@ namespace Avalonia.Collections if (hasValidation) { - Validate(item); + Validate!(item); } _inner.Insert(insertIndex++, item); - if (willRaiseCollectionChanged) - { - notificationItems.Add(item); - } + notificationItems?.Add(item); } while (en.MoveNext()); - NotifyAdd(notificationItems, index); + if (notificationItems is not null) + NotifyAdd(notificationItems, index); } } } @@ -501,7 +501,7 @@ namespace Avalonia.Collections /// The items. public virtual void RemoveAll(IEnumerable items) { - Contract.Requires(items != null); + _ = items ?? throw new ArgumentNullException(nameof(items)); foreach (var i in items) { @@ -537,17 +537,17 @@ namespace Avalonia.Collections } /// - int IList.Add(object value) + int IList.Add(object? value) { int index = Count; - Add((T)value); + Add((T)value!); return index; } /// - bool IList.Contains(object value) + bool IList.Contains(object? value) { - return Contains((T)value); + return Contains((T)value!); } /// @@ -557,21 +557,21 @@ namespace Avalonia.Collections } /// - int IList.IndexOf(object value) + int IList.IndexOf(object? value) { - return IndexOf((T)value); + return IndexOf((T)value!); } /// - void IList.Insert(int index, object value) + void IList.Insert(int index, object? value) { - Insert(index, (T)value); + Insert(index, (T)value!); } /// - void IList.Remove(object value) + void IList.Remove(object? value) { - Remove((T)value); + Remove((T)value!); } /// @@ -631,8 +631,7 @@ namespace Avalonia.Collections // We can't cast array of value type to object[], so we don't support // widening of primitive types here. // - object[] objects = array as object[]; - if (objects == null) + if (array is not object?[] objects) { throw new ArgumentException("Invalid array type"); } @@ -653,7 +652,7 @@ namespace Avalonia.Collections } /// - Delegate[] INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList(); + Delegate[]? INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList(); /// /// Raises the event with an add action. @@ -752,7 +751,7 @@ namespace Avalonia.Collections public T Current => _innerEnumerator.Current; - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; public void Dispose() { diff --git a/src/Avalonia.Base/Collections/AvaloniaListConverter.cs b/src/Avalonia.Base/Collections/AvaloniaListConverter.cs index f3e22bfe69..444cdec144 100644 --- a/src/Avalonia.Base/Collections/AvaloniaListConverter.cs +++ b/src/Avalonia.Base/Collections/AvaloniaListConverter.cs @@ -3,6 +3,8 @@ using System.ComponentModel; using System.Globalization; using Avalonia.Utilities; +#nullable enable + namespace Avalonia.Collections { /// diff --git a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs index b52829a60f..5f3c3964f7 100644 --- a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs +++ b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs @@ -5,6 +5,8 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Reactive.Disposables; +#nullable enable + namespace Avalonia.Collections { /// @@ -194,7 +196,7 @@ namespace Avalonia.Collections tracked.Remove(inpc); } }, - null); + () => throw new NotSupportedException("Collection reset not supported.")); return Disposable.Create(() => { diff --git a/src/Avalonia.Base/Collections/IAvaloniaList.cs b/src/Avalonia.Base/Collections/IAvaloniaList.cs index 250d4faeb9..c28fb835e0 100644 --- a/src/Avalonia.Base/Collections/IAvaloniaList.cs +++ b/src/Avalonia.Base/Collections/IAvaloniaList.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable enable + namespace Avalonia.Collections { /// diff --git a/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs b/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs index a6a5953827..09622dceba 100644 --- a/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs +++ b/src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +#nullable enable + namespace Avalonia.Collections { /// diff --git a/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs b/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs index fe9ef667b0..7a8c2325e6 100644 --- a/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs +++ b/src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs @@ -4,6 +4,8 @@ using System.Reactive.Linq; using Avalonia.Reactive; using Avalonia.Utilities; +#nullable enable + namespace Avalonia.Collections { public static class NotifyCollectionChangedExtensions @@ -16,7 +18,7 @@ namespace Avalonia.Collections public static IObservable GetWeakCollectionChangedObservable( this INotifyCollectionChanged collection) { - Contract.Requires(collection != null); + _ = collection ?? throw new ArgumentNullException(nameof(collection)); return new WeakCollectionChangedObservable(new WeakReference(collection)); } @@ -33,8 +35,8 @@ namespace Avalonia.Collections this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler) { - Contract.Requires(collection != null); - Contract.Requires(handler != null); + _ = collection ?? throw new ArgumentNullException(nameof(collection)); + _ = handler ?? throw new ArgumentNullException(nameof(handler)); return collection.GetWeakCollectionChangedObservable() .Subscribe(e => handler(collection, e)); @@ -52,8 +54,8 @@ namespace Avalonia.Collections this INotifyCollectionChanged collection, Action handler) { - Contract.Requires(collection != null); - Contract.Requires(handler != null); + _ = collection ?? throw new ArgumentNullException(nameof(collection)); + _ = handler ?? throw new ArgumentNullException(nameof(handler)); return collection.GetWeakCollectionChangedObservable().Subscribe(handler); } diff --git a/src/Avalonia.Base/Collections/Pooled/ClearMode.cs b/src/Avalonia.Base/Collections/Pooled/ClearMode.cs index d78ac8feab..f13538dce3 100644 --- a/src/Avalonia.Base/Collections/Pooled/ClearMode.cs +++ b/src/Avalonia.Base/Collections/Pooled/ClearMode.cs @@ -1,6 +1,8 @@ // This source file is adapted from the Collections.Pooled. // (https://github.com/jtmueller/Collections.Pooled/tree/master/Collections.Pooled/) +#nullable enable + namespace Avalonia.Collections.Pooled { /// diff --git a/src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs b/src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs index 2b15388a13..6f89cb7728 100644 --- a/src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs +++ b/src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +#nullable enable + namespace Avalonia.Collections.Pooled { internal sealed class ICollectionDebugView diff --git a/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs b/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs index 7a233a62ab..7ac22d2baf 100644 --- a/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs +++ b/src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +#nullable enable + namespace Avalonia.Collections.Pooled { /// diff --git a/src/Avalonia.Base/Collections/Pooled/PooledList.cs b/src/Avalonia.Base/Collections/Pooled/PooledList.cs index 2cd9758f12..73cd602948 100644 --- a/src/Avalonia.Base/Collections/Pooled/PooledList.cs +++ b/src/Avalonia.Base/Collections/Pooled/PooledList.cs @@ -8,10 +8,13 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Threading; +#nullable enable + namespace Avalonia.Collections.Pooled { /// @@ -38,7 +41,7 @@ namespace Avalonia.Collections.Pooled [NonSerialized] private ArrayPool _pool; [NonSerialized] - private object _syncRoot; + private object? _syncRoot; private T[] _items; // Do not rename (binary serialization) private int _size; // Do not rename (binary serialization) @@ -375,7 +378,7 @@ namespace Avalonia.Collections.Pooled { if (_syncRoot == null) { - Interlocked.CompareExchange(ref _syncRoot, new object(), null); + Interlocked.CompareExchange(ref _syncRoot, new object(), null); } return _syncRoot; } @@ -407,14 +410,14 @@ namespace Avalonia.Collections.Pooled } } - private static bool IsCompatibleObject(object value) + private static bool IsCompatibleObject(object? value) { // Non-null values are fine. Only accept nulls if T is a class or Nullable. // Note that default(T) is not equal to null for value types except when T is Nullable. return ((value is T) || (value == null && default(T) == null)); } - object IList.this[int index] + object? IList.this[int index] { get { @@ -426,7 +429,7 @@ namespace Avalonia.Collections.Pooled try { - this[index] = (T)value; + this[index] = (T)value!; } catch (InvalidCastException) { @@ -466,13 +469,13 @@ namespace Avalonia.Collections.Pooled _items[size] = item; } - int IList.Add(object item) + int IList.Add(object? item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow(item, ExceptionArgument.item); try { - Add((T)item); + Add((T)item!); } catch (InvalidCastException) { @@ -545,7 +548,7 @@ namespace Avalonia.Collections.Pooled /// the search value should be inserted into the list in order for the list /// to remain sorted. /// - public int BinarySearch(int index, int count, T item, IComparer comparer) + public int BinarySearch(int index, int count, T item, IComparer? comparer) { if (index < 0) ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); @@ -608,11 +611,11 @@ namespace Avalonia.Collections.Pooled return _size != 0 && IndexOf(item) != -1; } - bool IList.Contains(object item) + bool IList.Contains(object? item) { if (IsCompatibleObject(item)) { - return Contains((T)item); + return Contains((T)item!); } return false; } @@ -693,7 +696,7 @@ namespace Avalonia.Collections.Pooled public bool Exists(Func match) => FindIndex(match) != -1; - public bool TryFind(Func match, out T result) + public bool TryFind(Func match, [MaybeNullWhen(false)] out T result) { if (match == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); @@ -753,7 +756,7 @@ namespace Avalonia.Collections.Pooled return -1; } - public bool TryFindLast(Func match, out T result) + public bool TryFindLast(Func match, [MaybeNullWhen(false)] out T result) { if (match is null) { @@ -886,11 +889,11 @@ namespace Avalonia.Collections.Pooled public int IndexOf(T item) => Array.IndexOf(_items, item, 0, _size); - int IList.IndexOf(object item) + int IList.IndexOf(object? item) { if (IsCompatibleObject(item)) { - return IndexOf((T)item); + return IndexOf((T)item!); } return -1; } @@ -947,13 +950,13 @@ namespace Avalonia.Collections.Pooled _version++; } - void IList.Insert(int index, object item) + void IList.Insert(int index, object? item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow(item, ExceptionArgument.item); try { - Insert(index, (T)item); + Insert(index, (T)item!); } catch (InvalidCastException) { @@ -1155,11 +1158,11 @@ namespace Avalonia.Collections.Pooled return false; } - void IList.Remove(object item) + void IList.Remove(object? item) { if (IsCompatibleObject(item)) { - Remove((T)item); + Remove((T)item!); } } @@ -1225,7 +1228,7 @@ namespace Avalonia.Collections.Pooled if (_clearOnFree) { // Clear the removed element so that the gc can reclaim the reference. - _items[_size] = default; + _items[_size] = default!; } } @@ -1315,7 +1318,7 @@ namespace Avalonia.Collections.Pooled /// /// This method uses the Array.Sort method to sort the elements. /// - public void Sort(int index, int count, IComparer comparer) + public void Sort(int index, int count, IComparer? comparer) { if (index < 0) ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); @@ -1452,7 +1455,7 @@ namespace Avalonia.Collections.Pooled private readonly PooledList _list; private int _index; private readonly int _version; - private T _current; + private T? _current; internal Enumerator(PooledList list) { @@ -1491,9 +1494,9 @@ namespace Avalonia.Collections.Pooled return false; } - public T Current => _current; + public T Current => _current!; - object IEnumerator.Current + object? IEnumerator.Current { get { diff --git a/src/Avalonia.Base/Collections/Pooled/PooledStack.cs b/src/Avalonia.Base/Collections/Pooled/PooledStack.cs index 104a7f97e9..8a03c6f5e4 100644 --- a/src/Avalonia.Base/Collections/Pooled/PooledStack.cs +++ b/src/Avalonia.Base/Collections/Pooled/PooledStack.cs @@ -20,6 +20,8 @@ using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Threading; +#nullable enable + namespace Avalonia.Collections.Pooled { /// @@ -34,7 +36,7 @@ namespace Avalonia.Collections.Pooled [NonSerialized] private ArrayPool _pool; [NonSerialized] - private object _syncRoot; + private object? _syncRoot; private T[] _array; // Storage for stack elements. Do not rename (binary serialization) private int _size; // Number of items in the stack. Do not rename (binary serialization) @@ -237,7 +239,7 @@ namespace Avalonia.Collections.Pooled { if (_syncRoot == null) { - Interlocked.CompareExchange(ref _syncRoot, new object(), null); + Interlocked.CompareExchange(ref _syncRoot, new object(), null); } return _syncRoot; } @@ -456,7 +458,7 @@ namespace Avalonia.Collections.Pooled return array[size]; } - public bool TryPeek(out T result) + public bool TryPeek([MaybeNullWhen(false)] out T result) { int size = _size - 1; T[] array = _array; @@ -492,12 +494,12 @@ namespace Avalonia.Collections.Pooled T item = array[size]; if (_clearOnFree) { - array[size] = default; // Free memory quicker. + array[size] = default!; // Free memory quicker. } return item; } - public bool TryPop(out T result) + public bool TryPop([MaybeNullWhen(false)] out T result) { int size = _size - 1; T[] array = _array; @@ -513,7 +515,7 @@ namespace Avalonia.Collections.Pooled result = array[size]; if (_clearOnFree) { - array[size] = default; // Free memory quicker. + array[size] = default!; // Free memory quicker. } return true; } @@ -574,7 +576,7 @@ namespace Avalonia.Collections.Pooled throw new InvalidOperationException("Stack was empty."); } - private void ReturnArray(T[] replaceWith = null) + private void ReturnArray(T[]? replaceWith = null) { if (_array?.Length > 0) { @@ -625,7 +627,7 @@ namespace Avalonia.Collections.Pooled private readonly PooledStack _stack; private readonly int _version; private int _index; - private T _currentElement; + private T? _currentElement; internal Enumerator(PooledStack stack) { @@ -672,7 +674,7 @@ namespace Avalonia.Collections.Pooled { if (_index < 0) ThrowEnumerationNotStartedOrEnded(); - return _currentElement; + return _currentElement!; } } @@ -682,7 +684,7 @@ namespace Avalonia.Collections.Pooled throw new InvalidOperationException(_index == -2 ? "Enumeration was not started." : "Enumeration has ended."); } - object IEnumerator.Current + object? IEnumerator.Current { get { return Current; } } diff --git a/src/Avalonia.Base/Collections/Pooled/StackDebugView.cs b/src/Avalonia.Base/Collections/Pooled/StackDebugView.cs index b042388079..b55ac110c6 100644 --- a/src/Avalonia.Base/Collections/Pooled/StackDebugView.cs +++ b/src/Avalonia.Base/Collections/Pooled/StackDebugView.cs @@ -5,6 +5,8 @@ using System; using System.Diagnostics; +#nullable enable + namespace Avalonia.Collections.Pooled { internal sealed class StackDebugView diff --git a/src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs b/src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs index 74558229c3..3237286107 100644 --- a/src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs +++ b/src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs @@ -38,108 +38,128 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; +#nullable enable + namespace Avalonia.Collections.Pooled { internal static class ThrowHelper { + [DoesNotReturn] internal static void ThrowArrayTypeMismatchException() { throw new ArrayTypeMismatchException(); } + [DoesNotReturn] internal static void ThrowIndexOutOfRangeException() { throw new IndexOutOfRangeException(); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException(); } + [DoesNotReturn] internal static void ThrowArgumentException_DestinationTooShort() { throw new ArgumentException("Destination too short."); } + [DoesNotReturn] internal static void ThrowArgumentException_OverlapAlignmentMismatch() { throw new ArgumentException("Overlap alignment mismatch."); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRange_IndexException() { throw GetArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() { throw GetArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() { throw GetArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() { throw GetArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() { throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() { throw GetArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); } + [DoesNotReturn] internal static void ThrowWrongKeyTypeArgumentException(T key, Type targetType) { // Generic key to move the boxing to the right hand side of throw - throw GetWrongKeyTypeArgumentException((object)key, targetType); + throw GetWrongKeyTypeArgumentException((object?)key, targetType); } + [DoesNotReturn] internal static void ThrowWrongValueTypeArgumentException(T value, Type targetType) { // Generic key to move the boxing to the right hand side of throw - throw GetWrongValueTypeArgumentException((object)value, targetType); + throw GetWrongValueTypeArgumentException((object?)value, targetType); } - private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key) + private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object? key) { return new ArgumentException($"Error adding duplicate with key: {key}."); } + [DoesNotReturn] internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) { // Generic key to move the boxing to the right hand side of throw - throw GetAddingDuplicateWithKeyArgumentException((object)key); + throw GetAddingDuplicateWithKeyArgumentException((object?)key); } + [DoesNotReturn] internal static void ThrowKeyNotFoundException(T key) { // Generic key to move the boxing to the right hand side of throw - throw GetKeyNotFoundException((object)key); + throw GetKeyNotFoundException((object?)key); } + [DoesNotReturn] internal static void ThrowArgumentException(ExceptionResource resource) { throw GetArgumentException(resource); } + [DoesNotReturn] internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) { throw GetArgumentException(resource, argument); @@ -150,141 +170,169 @@ namespace Avalonia.Collections.Pooled return new ArgumentNullException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionArgument argument) { throw GetArgumentNullException(argument); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionResource resource) { throw new ArgumentNullException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource) { throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) { throw new ArgumentOutOfRangeException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) { throw GetArgumentOutOfRangeException(argument, resource); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource) { throw GetArgumentOutOfRangeException(argument, paramNumber, resource); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource) { throw GetInvalidOperationException(resource); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e) { throw new InvalidOperationException(GetResourceString(resource), e); } + [DoesNotReturn] internal static void ThrowSerializationException(ExceptionResource resource) { throw new SerializationException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowSecurityException(ExceptionResource resource) { throw new System.Security.SecurityException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowRankException(ExceptionResource resource) { throw new RankException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowNotSupportedException(ExceptionResource resource) { throw new NotSupportedException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) { throw new UnauthorizedAccessException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) { throw new ObjectDisposedException(objectName, GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowObjectDisposedException(ExceptionResource resource) { throw new ObjectDisposedException(null, GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowNotSupportedException() { throw new NotSupportedException(); } + [DoesNotReturn] internal static void ThrowAggregateException(List exceptions) { throw new AggregateException(exceptions); } + [DoesNotReturn] internal static void ThrowOutOfMemoryException() { throw new OutOfMemoryException(); } + [DoesNotReturn] internal static void ThrowArgumentException_Argument_InvalidArrayType() { throw new ArgumentException("Invalid array type."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted() { throw new InvalidOperationException("Enumeration has not started."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded() { throw new InvalidOperationException("Enumeration has ended."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_EnumCurrent(int index) { throw GetInvalidOperationException_EnumCurrent(index); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() { throw new InvalidOperationException("Collection was modified during enumeration."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() { throw new InvalidOperationException("Invalid enumerator state: enumeration cannot proceed."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_NoValue() { throw new InvalidOperationException("No value provided."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported() { throw new InvalidOperationException("Concurrent operations are not supported."); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_HandleIsNotInitialized() { throw new InvalidOperationException("Handle is not initialized."); } + [DoesNotReturn] internal static void ThrowFormatException_BadFormatSpecifier() { throw new FormatException("Bad format specifier."); @@ -300,17 +348,17 @@ namespace Avalonia.Collections.Pooled return new InvalidOperationException(GetResourceString(resource)); } - private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType) + private static ArgumentException GetWrongKeyTypeArgumentException(object? key, Type targetType) { return new ArgumentException($"Wrong key type. Expected {targetType}, got: '{key}'.", nameof(key)); } - private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType) + private static ArgumentException GetWrongValueTypeArgumentException(object? value, Type targetType) { return new ArgumentException($"Wrong value type. Expected {targetType}, got: '{value}'.", nameof(value)); } - private static KeyNotFoundException GetKeyNotFoundException(object key) + private static KeyNotFoundException GetKeyNotFoundException(object? key) { return new KeyNotFoundException($"Key not found: {key}"); } @@ -342,7 +390,7 @@ namespace Avalonia.Collections.Pooled // Aggressively inline so the jit evaluates the if in place and either drops the call altogether // Or just leaves null test and call to the Non-returning ThrowHelper.ThrowArgumentNullException [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void IfNullAndNullsAreIllegalThenThrow(object value, ExceptionArgument argName) + internal static void IfNullAndNullsAreIllegalThenThrow(object? value, ExceptionArgument argName) { // Note that default(T) is not equal to null for value types except when T is Nullable. if (!(default(T) == null) && value == null) diff --git a/src/Avalonia.Styling/Controls/ResourceDictionary.cs b/src/Avalonia.Styling/Controls/ResourceDictionary.cs index c56dd74143..e797f8cf8b 100644 --- a/src/Avalonia.Styling/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Styling/Controls/ResourceDictionary.cs @@ -68,7 +68,8 @@ namespace Avalonia.Controls { x.RemoveOwner(Owner); } - }, null); + }, + () => throw new NotSupportedException("Dictionary reset not supported")); } return _mergedDictionaries;