Browse Source

Merge branch 'master' into dialog-microcom

pull/7028/head
Max Katz 5 years ago
committed by GitHub
parent
commit
4e2a0e1321
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  2. 61
      src/Avalonia.Base/Collections/AvaloniaList.cs
  3. 2
      src/Avalonia.Base/Collections/AvaloniaListConverter.cs
  4. 4
      src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
  5. 2
      src/Avalonia.Base/Collections/IAvaloniaList.cs
  6. 2
      src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs
  7. 12
      src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs
  8. 2
      src/Avalonia.Base/Collections/Pooled/ClearMode.cs
  9. 2
      src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs
  10. 2
      src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs
  11. 49
      src/Avalonia.Base/Collections/Pooled/PooledList.cs
  12. 22
      src/Avalonia.Base/Collections/Pooled/PooledStack.cs
  13. 2
      src/Avalonia.Base/Collections/Pooled/StackDebugView.cs
  14. 66
      src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs
  15. 3
      src/Avalonia.Styling/Controls/ResourceDictionary.cs

6
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@ -6,6 +6,8 @@ using System.ComponentModel;
using System.Linq; using System.Linq;
using Avalonia.Data.Core; using Avalonia.Data.Core;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>
@ -31,12 +33,12 @@ namespace Avalonia.Collections
/// <summary> /// <summary>
/// Occurs when the collection changes. /// Occurs when the collection changes.
/// </summary> /// </summary>
public event NotifyCollectionChangedEventHandler CollectionChanged; public event NotifyCollectionChangedEventHandler? CollectionChanged;
/// <summary> /// <summary>
/// Raised when a property on the collection changes. /// Raised when a property on the collection changes.
/// </summary> /// </summary>
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
/// <inheritdoc/> /// <inheritdoc/>
public int Count => _inner.Count; public int Count => _inner.Count;

61
src/Avalonia.Base/Collections/AvaloniaList.cs

@ -6,6 +6,8 @@ using System.ComponentModel;
using System.Linq; using System.Linq;
using Avalonia.Diagnostics; using Avalonia.Diagnostics;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>
@ -53,7 +55,7 @@ namespace Avalonia.Collections
public class AvaloniaList<T> : IAvaloniaList<T>, IList, INotifyCollectionChangedDebug public class AvaloniaList<T> : IAvaloniaList<T>, IList, INotifyCollectionChangedDebug
{ {
private readonly List<T> _inner; private readonly List<T> _inner;
private NotifyCollectionChangedEventHandler _collectionChanged; private NotifyCollectionChangedEventHandler? _collectionChanged;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AvaloniaList{T}"/> class. /// Initializes a new instance of the <see cref="AvaloniaList{T}"/> class.
@ -102,7 +104,7 @@ namespace Avalonia.Collections
/// <summary> /// <summary>
/// Raised when a property on the collection changes. /// Raised when a property on the collection changes.
/// </summary> /// </summary>
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
/// <summary> /// <summary>
/// Gets the number of items in the collection. /// 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 /// Gets or sets a validation routine that can be used to validate items before they are
/// added. /// added.
/// </summary> /// </summary>
public Action<T> Validate { get; set; } public Action<T>? Validate { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
bool IList.IsFixedSize => false; bool IList.IsFixedSize => false;
@ -133,7 +135,7 @@ namespace Avalonia.Collections
bool ICollection.IsSynchronized => false; bool ICollection.IsSynchronized => false;
/// <inheritdoc/> /// <inheritdoc/>
object ICollection.SyncRoot => null; object? ICollection.SyncRoot => null;
/// <inheritdoc/> /// <inheritdoc/>
bool ICollection<T>.IsReadOnly => false; bool ICollection<T>.IsReadOnly => false;
@ -178,10 +180,10 @@ namespace Avalonia.Collections
/// </summary> /// </summary>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The item.</returns> /// <returns>The item.</returns>
object IList.this[int index] object? IList.this[int index]
{ {
get { return this[index]; } get { return this[index]; }
set { this[index] = (T)value; } set { this[index] = (T)value!; }
} }
/// <summary> /// <summary>
@ -318,7 +320,7 @@ namespace Avalonia.Collections
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
public virtual void InsertRange(int index, IEnumerable<T> items) public virtual void InsertRange(int index, IEnumerable<T> items)
{ {
Contract.Requires<ArgumentNullException>(items != null); _ = items ?? throw new ArgumentNullException(nameof(items));
bool willRaiseCollectionChanged = _collectionChanged != null; bool willRaiseCollectionChanged = _collectionChanged != null;
bool hasValidation = Validate != null; bool hasValidation = Validate != null;
@ -333,7 +335,7 @@ namespace Avalonia.Collections
{ {
foreach (T item in collection) foreach (T item in collection)
{ {
Validate(item); Validate!(item);
} }
} }
@ -354,7 +356,7 @@ namespace Avalonia.Collections
if (hasValidation) if (hasValidation)
{ {
Validate(item); Validate!(item);
} }
_inner.Insert(insertIndex++, item); _inner.Insert(insertIndex++, item);
@ -372,7 +374,7 @@ namespace Avalonia.Collections
if (en.MoveNext()) if (en.MoveNext())
{ {
// Avoid allocating list for collection notification if there is no event subscriptions. // Avoid allocating list for collection notification if there is no event subscriptions.
List<T> notificationItems = willRaiseCollectionChanged ? List<T>? notificationItems = willRaiseCollectionChanged ?
new List<T>() : new List<T>() :
null; null;
@ -384,19 +386,17 @@ namespace Avalonia.Collections
if (hasValidation) if (hasValidation)
{ {
Validate(item); Validate!(item);
} }
_inner.Insert(insertIndex++, item); _inner.Insert(insertIndex++, item);
if (willRaiseCollectionChanged) notificationItems?.Add(item);
{
notificationItems.Add(item);
}
} while (en.MoveNext()); } while (en.MoveNext());
NotifyAdd(notificationItems, index); if (notificationItems is not null)
NotifyAdd(notificationItems, index);
} }
} }
} }
@ -501,7 +501,7 @@ namespace Avalonia.Collections
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
public virtual void RemoveAll(IEnumerable<T> items) public virtual void RemoveAll(IEnumerable<T> items)
{ {
Contract.Requires<ArgumentNullException>(items != null); _ = items ?? throw new ArgumentNullException(nameof(items));
var hItems = new HashSet<T>(items); var hItems = new HashSet<T>(items);
@ -550,17 +550,17 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
int IList.Add(object value) int IList.Add(object? value)
{ {
int index = Count; int index = Count;
Add((T)value); Add((T)value!);
return index; return index;
} }
/// <inheritdoc/> /// <inheritdoc/>
bool IList.Contains(object value) bool IList.Contains(object? value)
{ {
return Contains((T)value); return Contains((T)value!);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -570,21 +570,21 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
int IList.IndexOf(object value) int IList.IndexOf(object? value)
{ {
return IndexOf((T)value); return IndexOf((T)value!);
} }
/// <inheritdoc/> /// <inheritdoc/>
void IList.Insert(int index, object value) void IList.Insert(int index, object? value)
{ {
Insert(index, (T)value); Insert(index, (T)value!);
} }
/// <inheritdoc/> /// <inheritdoc/>
void IList.Remove(object value) void IList.Remove(object? value)
{ {
Remove((T)value); Remove((T)value!);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -644,8 +644,7 @@ namespace Avalonia.Collections
// We can't cast array of value type to object[], so we don't support // We can't cast array of value type to object[], so we don't support
// widening of primitive types here. // widening of primitive types here.
// //
object[] objects = array as object[]; if (array is not object?[] objects)
if (objects == null)
{ {
throw new ArgumentException("Invalid array type"); throw new ArgumentException("Invalid array type");
} }
@ -666,7 +665,7 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
Delegate[] INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList(); Delegate[]? INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList();
/// <summary> /// <summary>
/// Raises the <see cref="CollectionChanged"/> event with an add action. /// Raises the <see cref="CollectionChanged"/> event with an add action.
@ -765,7 +764,7 @@ namespace Avalonia.Collections
public T Current => _innerEnumerator.Current; public T Current => _innerEnumerator.Current;
object IEnumerator.Current => Current; object? IEnumerator.Current => Current;
public void Dispose() public void Dispose()
{ {

2
src/Avalonia.Base/Collections/AvaloniaListConverter.cs

@ -3,6 +3,8 @@ using System.ComponentModel;
using System.Globalization; using System.Globalization;
using Avalonia.Utilities; using Avalonia.Utilities;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>

4
src/Avalonia.Base/Collections/AvaloniaListExtensions.cs

@ -5,6 +5,8 @@ using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Reactive.Disposables; using System.Reactive.Disposables;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>
@ -194,7 +196,7 @@ namespace Avalonia.Collections
tracked.Remove(inpc); tracked.Remove(inpc);
} }
}, },
null); () => throw new NotSupportedException("Collection reset not supported."));
return Disposable.Create(() => return Disposable.Create(() =>
{ {

2
src/Avalonia.Base/Collections/IAvaloniaList.cs

@ -1,5 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>

2
src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs

@ -2,6 +2,8 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
/// <summary> /// <summary>

12
src/Avalonia.Base/Collections/NotifyCollectionChangedExtensions.cs

@ -4,6 +4,8 @@ using System.Reactive.Linq;
using Avalonia.Reactive; using Avalonia.Reactive;
using Avalonia.Utilities; using Avalonia.Utilities;
#nullable enable
namespace Avalonia.Collections namespace Avalonia.Collections
{ {
public static class NotifyCollectionChangedExtensions public static class NotifyCollectionChangedExtensions
@ -16,7 +18,7 @@ namespace Avalonia.Collections
public static IObservable<NotifyCollectionChangedEventArgs> GetWeakCollectionChangedObservable( public static IObservable<NotifyCollectionChangedEventArgs> GetWeakCollectionChangedObservable(
this INotifyCollectionChanged collection) this INotifyCollectionChanged collection)
{ {
Contract.Requires<ArgumentNullException>(collection != null); _ = collection ?? throw new ArgumentNullException(nameof(collection));
return new WeakCollectionChangedObservable(new WeakReference<INotifyCollectionChanged>(collection)); return new WeakCollectionChangedObservable(new WeakReference<INotifyCollectionChanged>(collection));
} }
@ -33,8 +35,8 @@ namespace Avalonia.Collections
this INotifyCollectionChanged collection, this INotifyCollectionChanged collection,
NotifyCollectionChangedEventHandler handler) NotifyCollectionChangedEventHandler handler)
{ {
Contract.Requires<ArgumentNullException>(collection != null); _ = collection ?? throw new ArgumentNullException(nameof(collection));
Contract.Requires<ArgumentNullException>(handler != null); _ = handler ?? throw new ArgumentNullException(nameof(handler));
return collection.GetWeakCollectionChangedObservable() return collection.GetWeakCollectionChangedObservable()
.Subscribe(e => handler(collection, e)); .Subscribe(e => handler(collection, e));
@ -52,8 +54,8 @@ namespace Avalonia.Collections
this INotifyCollectionChanged collection, this INotifyCollectionChanged collection,
Action<NotifyCollectionChangedEventArgs> handler) Action<NotifyCollectionChangedEventArgs> handler)
{ {
Contract.Requires<ArgumentNullException>(collection != null); _ = collection ?? throw new ArgumentNullException(nameof(collection));
Contract.Requires<ArgumentNullException>(handler != null); _ = handler ?? throw new ArgumentNullException(nameof(handler));
return collection.GetWeakCollectionChangedObservable().Subscribe(handler); return collection.GetWeakCollectionChangedObservable().Subscribe(handler);
} }

2
src/Avalonia.Base/Collections/Pooled/ClearMode.cs

@ -1,6 +1,8 @@
// This source file is adapted from the Collections.Pooled. // This source file is adapted from the Collections.Pooled.
// (https://github.com/jtmueller/Collections.Pooled/tree/master/Collections.Pooled/) // (https://github.com/jtmueller/Collections.Pooled/tree/master/Collections.Pooled/)
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
/// <summary> /// <summary>

2
src/Avalonia.Base/Collections/Pooled/ICollectionDebugView.cs

@ -6,6 +6,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
internal sealed class ICollectionDebugView<T> internal sealed class ICollectionDebugView<T>

2
src/Avalonia.Base/Collections/Pooled/IReadOnlyPooledList.cs

@ -4,6 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
/// <summary> /// <summary>

49
src/Avalonia.Base/Collections/Pooled/PooledList.cs

@ -8,10 +8,13 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading; using System.Threading;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
/// <summary> /// <summary>
@ -38,7 +41,7 @@ namespace Avalonia.Collections.Pooled
[NonSerialized] [NonSerialized]
private ArrayPool<T> _pool; private ArrayPool<T> _pool;
[NonSerialized] [NonSerialized]
private object _syncRoot; private object? _syncRoot;
private T[] _items; // Do not rename (binary serialization) private T[] _items; // Do not rename (binary serialization)
private int _size; // Do not rename (binary serialization) private int _size; // Do not rename (binary serialization)
@ -375,7 +378,7 @@ namespace Avalonia.Collections.Pooled
{ {
if (_syncRoot == null) if (_syncRoot == null)
{ {
Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null); Interlocked.CompareExchange<object?>(ref _syncRoot, new object(), null);
} }
return _syncRoot; 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<U>. // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>.
// Note that default(T) is not equal to null for value types except when T is Nullable<U>. // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
return ((value is T) || (value == null && default(T) == null)); return ((value is T) || (value == null && default(T) == null));
} }
object IList.this[int index] object? IList.this[int index]
{ {
get get
{ {
@ -426,7 +429,7 @@ namespace Avalonia.Collections.Pooled
try try
{ {
this[index] = (T)value; this[index] = (T)value!;
} }
catch (InvalidCastException) catch (InvalidCastException)
{ {
@ -466,13 +469,13 @@ namespace Avalonia.Collections.Pooled
_items[size] = item; _items[size] = item;
} }
int IList.Add(object item) int IList.Add(object? item)
{ {
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
try try
{ {
Add((T)item); Add((T)item!);
} }
catch (InvalidCastException) catch (InvalidCastException)
{ {
@ -545,7 +548,7 @@ namespace Avalonia.Collections.Pooled
/// the search value should be inserted into the list in order for the list /// the search value should be inserted into the list in order for the list
/// to remain sorted. /// to remain sorted.
/// </para></remarks> /// </para></remarks>
public int BinarySearch(int index, int count, T item, IComparer<T> comparer) public int BinarySearch(int index, int count, T item, IComparer<T>? comparer)
{ {
if (index < 0) if (index < 0)
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
@ -608,11 +611,11 @@ namespace Avalonia.Collections.Pooled
return _size != 0 && IndexOf(item) != -1; return _size != 0 && IndexOf(item) != -1;
} }
bool IList.Contains(object item) bool IList.Contains(object? item)
{ {
if (IsCompatibleObject(item)) if (IsCompatibleObject(item))
{ {
return Contains((T)item); return Contains((T)item!);
} }
return false; return false;
} }
@ -693,7 +696,7 @@ namespace Avalonia.Collections.Pooled
public bool Exists(Func<T, bool> match) public bool Exists(Func<T, bool> match)
=> FindIndex(match) != -1; => FindIndex(match) != -1;
public bool TryFind(Func<T, bool> match, out T result) public bool TryFind(Func<T, bool> match, [MaybeNullWhen(false)] out T result)
{ {
if (match == null) if (match == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
@ -753,7 +756,7 @@ namespace Avalonia.Collections.Pooled
return -1; return -1;
} }
public bool TryFindLast(Func<T, bool> match, out T result) public bool TryFindLast(Func<T, bool> match, [MaybeNullWhen(false)] out T result)
{ {
if (match is null) if (match is null)
{ {
@ -886,11 +889,11 @@ namespace Avalonia.Collections.Pooled
public int IndexOf(T item) public int IndexOf(T item)
=> Array.IndexOf(_items, item, 0, _size); => Array.IndexOf(_items, item, 0, _size);
int IList.IndexOf(object item) int IList.IndexOf(object? item)
{ {
if (IsCompatibleObject(item)) if (IsCompatibleObject(item))
{ {
return IndexOf((T)item); return IndexOf((T)item!);
} }
return -1; return -1;
} }
@ -947,13 +950,13 @@ namespace Avalonia.Collections.Pooled
_version++; _version++;
} }
void IList.Insert(int index, object item) void IList.Insert(int index, object? item)
{ {
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
try try
{ {
Insert(index, (T)item); Insert(index, (T)item!);
} }
catch (InvalidCastException) catch (InvalidCastException)
{ {
@ -1155,11 +1158,11 @@ namespace Avalonia.Collections.Pooled
return false; return false;
} }
void IList.Remove(object item) void IList.Remove(object? item)
{ {
if (IsCompatibleObject(item)) if (IsCompatibleObject(item))
{ {
Remove((T)item); Remove((T)item!);
} }
} }
@ -1225,7 +1228,7 @@ namespace Avalonia.Collections.Pooled
if (_clearOnFree) if (_clearOnFree)
{ {
// Clear the removed element so that the gc can reclaim the reference. // 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. /// This method uses the Array.Sort method to sort the elements.
/// </summary> /// </summary>
public void Sort(int index, int count, IComparer<T> comparer) public void Sort(int index, int count, IComparer<T>? comparer)
{ {
if (index < 0) if (index < 0)
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
@ -1452,7 +1455,7 @@ namespace Avalonia.Collections.Pooled
private readonly PooledList<T> _list; private readonly PooledList<T> _list;
private int _index; private int _index;
private readonly int _version; private readonly int _version;
private T _current; private T? _current;
internal Enumerator(PooledList<T> list) internal Enumerator(PooledList<T> list)
{ {
@ -1491,9 +1494,9 @@ namespace Avalonia.Collections.Pooled
return false; return false;
} }
public T Current => _current; public T Current => _current!;
object IEnumerator.Current object? IEnumerator.Current
{ {
get get
{ {

22
src/Avalonia.Base/Collections/Pooled/PooledStack.cs

@ -20,6 +20,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading; using System.Threading;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
/// <summary> /// <summary>
@ -34,7 +36,7 @@ namespace Avalonia.Collections.Pooled
[NonSerialized] [NonSerialized]
private ArrayPool<T> _pool; private ArrayPool<T> _pool;
[NonSerialized] [NonSerialized]
private object _syncRoot; private object? _syncRoot;
private T[] _array; // Storage for stack elements. Do not rename (binary serialization) 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) 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) if (_syncRoot == null)
{ {
Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null); Interlocked.CompareExchange<object?>(ref _syncRoot, new object(), null);
} }
return _syncRoot; return _syncRoot;
} }
@ -456,7 +458,7 @@ namespace Avalonia.Collections.Pooled
return array[size]; return array[size];
} }
public bool TryPeek(out T result) public bool TryPeek([MaybeNullWhen(false)] out T result)
{ {
int size = _size - 1; int size = _size - 1;
T[] array = _array; T[] array = _array;
@ -492,12 +494,12 @@ namespace Avalonia.Collections.Pooled
T item = array[size]; T item = array[size];
if (_clearOnFree) if (_clearOnFree)
{ {
array[size] = default; // Free memory quicker. array[size] = default!; // Free memory quicker.
} }
return item; return item;
} }
public bool TryPop(out T result) public bool TryPop([MaybeNullWhen(false)] out T result)
{ {
int size = _size - 1; int size = _size - 1;
T[] array = _array; T[] array = _array;
@ -513,7 +515,7 @@ namespace Avalonia.Collections.Pooled
result = array[size]; result = array[size];
if (_clearOnFree) if (_clearOnFree)
{ {
array[size] = default; // Free memory quicker. array[size] = default!; // Free memory quicker.
} }
return true; return true;
} }
@ -574,7 +576,7 @@ namespace Avalonia.Collections.Pooled
throw new InvalidOperationException("Stack was empty."); throw new InvalidOperationException("Stack was empty.");
} }
private void ReturnArray(T[] replaceWith = null) private void ReturnArray(T[]? replaceWith = null)
{ {
if (_array?.Length > 0) if (_array?.Length > 0)
{ {
@ -625,7 +627,7 @@ namespace Avalonia.Collections.Pooled
private readonly PooledStack<T> _stack; private readonly PooledStack<T> _stack;
private readonly int _version; private readonly int _version;
private int _index; private int _index;
private T _currentElement; private T? _currentElement;
internal Enumerator(PooledStack<T> stack) internal Enumerator(PooledStack<T> stack)
{ {
@ -672,7 +674,7 @@ namespace Avalonia.Collections.Pooled
{ {
if (_index < 0) if (_index < 0)
ThrowEnumerationNotStartedOrEnded(); 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."); throw new InvalidOperationException(_index == -2 ? "Enumeration was not started." : "Enumeration has ended.");
} }
object IEnumerator.Current object? IEnumerator.Current
{ {
get { return Current; } get { return Current; }
} }

2
src/Avalonia.Base/Collections/Pooled/StackDebugView.cs

@ -5,6 +5,8 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
internal sealed class StackDebugView<T> internal sealed class StackDebugView<T>

66
src/Avalonia.Base/Collections/Pooled/ThrowHelper.cs

@ -38,108 +38,128 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
#nullable enable
namespace Avalonia.Collections.Pooled namespace Avalonia.Collections.Pooled
{ {
internal static class ThrowHelper internal static class ThrowHelper
{ {
[DoesNotReturn]
internal static void ThrowArrayTypeMismatchException() internal static void ThrowArrayTypeMismatchException()
{ {
throw new ArrayTypeMismatchException(); throw new ArrayTypeMismatchException();
} }
[DoesNotReturn]
internal static void ThrowIndexOutOfRangeException() internal static void ThrowIndexOutOfRangeException()
{ {
throw new IndexOutOfRangeException(); throw new IndexOutOfRangeException();
} }
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException() internal static void ThrowArgumentOutOfRangeException()
{ {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
[DoesNotReturn]
internal static void ThrowArgumentException_DestinationTooShort() internal static void ThrowArgumentException_DestinationTooShort()
{ {
throw new ArgumentException("Destination too short."); throw new ArgumentException("Destination too short.");
} }
[DoesNotReturn]
internal static void ThrowArgumentException_OverlapAlignmentMismatch() internal static void ThrowArgumentException_OverlapAlignmentMismatch()
{ {
throw new ArgumentException("Overlap alignment mismatch."); throw new ArgumentException("Overlap alignment mismatch.");
} }
[DoesNotReturn]
internal static void ThrowArgumentOutOfRange_IndexException() internal static void ThrowArgumentOutOfRange_IndexException()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.index, throw GetArgumentOutOfRangeException(ExceptionArgument.index,
ExceptionResource.ArgumentOutOfRange_Index); ExceptionResource.ArgumentOutOfRange_Index);
} }
[DoesNotReturn]
internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.index, throw GetArgumentOutOfRangeException(ExceptionArgument.index,
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
} }
[DoesNotReturn]
internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.value, throw GetArgumentOutOfRangeException(ExceptionArgument.value,
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
} }
[DoesNotReturn]
internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.length, throw GetArgumentOutOfRangeException(ExceptionArgument.length,
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
} }
[DoesNotReturn]
internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex, throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex,
ExceptionResource.ArgumentOutOfRange_Index); ExceptionResource.ArgumentOutOfRange_Index);
} }
[DoesNotReturn]
internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
{ {
throw GetArgumentOutOfRangeException(ExceptionArgument.count, throw GetArgumentOutOfRangeException(ExceptionArgument.count,
ExceptionResource.ArgumentOutOfRange_Count); ExceptionResource.ArgumentOutOfRange_Count);
} }
[DoesNotReturn]
internal static void ThrowWrongKeyTypeArgumentException<T>(T key, Type targetType) internal static void ThrowWrongKeyTypeArgumentException<T>(T key, Type targetType)
{ {
// Generic key to move the boxing to the right hand side of throw // 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>(T value, Type targetType) internal static void ThrowWrongValueTypeArgumentException<T>(T value, Type targetType)
{ {
// Generic key to move the boxing to the right hand side of throw // 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}."); return new ArgumentException($"Error adding duplicate with key: {key}.");
} }
[DoesNotReturn]
internal static void ThrowAddingDuplicateWithKeyArgumentException<T>(T key) internal static void ThrowAddingDuplicateWithKeyArgumentException<T>(T key)
{ {
// Generic key to move the boxing to the right hand side of throw // 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>(T key) internal static void ThrowKeyNotFoundException<T>(T key)
{ {
// Generic key to move the boxing to the right hand side of throw // 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) internal static void ThrowArgumentException(ExceptionResource resource)
{ {
throw GetArgumentException(resource); throw GetArgumentException(resource);
} }
[DoesNotReturn]
internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument)
{ {
throw GetArgumentException(resource, argument); throw GetArgumentException(resource, argument);
@ -150,141 +170,169 @@ namespace Avalonia.Collections.Pooled
return new ArgumentNullException(GetArgumentName(argument)); return new ArgumentNullException(GetArgumentName(argument));
} }
[DoesNotReturn]
internal static void ThrowArgumentNullException(ExceptionArgument argument) internal static void ThrowArgumentNullException(ExceptionArgument argument)
{ {
throw GetArgumentNullException(argument); throw GetArgumentNullException(argument);
} }
[DoesNotReturn]
internal static void ThrowArgumentNullException(ExceptionResource resource) internal static void ThrowArgumentNullException(ExceptionResource resource)
{ {
throw new ArgumentNullException(GetResourceString(resource)); throw new ArgumentNullException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource) internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource)
{ {
throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource)); throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument)
{ {
throw new ArgumentOutOfRangeException(GetArgumentName(argument)); throw new ArgumentOutOfRangeException(GetArgumentName(argument));
} }
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
{ {
throw GetArgumentOutOfRangeException(argument, resource); throw GetArgumentOutOfRangeException(argument, resource);
} }
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource) internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource)
{ {
throw GetArgumentOutOfRangeException(argument, paramNumber, resource); throw GetArgumentOutOfRangeException(argument, paramNumber, resource);
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException(ExceptionResource resource) internal static void ThrowInvalidOperationException(ExceptionResource resource)
{ {
throw GetInvalidOperationException(resource); throw GetInvalidOperationException(resource);
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e) internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e)
{ {
throw new InvalidOperationException(GetResourceString(resource), e); throw new InvalidOperationException(GetResourceString(resource), e);
} }
[DoesNotReturn]
internal static void ThrowSerializationException(ExceptionResource resource) internal static void ThrowSerializationException(ExceptionResource resource)
{ {
throw new SerializationException(GetResourceString(resource)); throw new SerializationException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowSecurityException(ExceptionResource resource) internal static void ThrowSecurityException(ExceptionResource resource)
{ {
throw new System.Security.SecurityException(GetResourceString(resource)); throw new System.Security.SecurityException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowRankException(ExceptionResource resource) internal static void ThrowRankException(ExceptionResource resource)
{ {
throw new RankException(GetResourceString(resource)); throw new RankException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowNotSupportedException(ExceptionResource resource) internal static void ThrowNotSupportedException(ExceptionResource resource)
{ {
throw new NotSupportedException(GetResourceString(resource)); throw new NotSupportedException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) internal static void ThrowUnauthorizedAccessException(ExceptionResource resource)
{ {
throw new UnauthorizedAccessException(GetResourceString(resource)); throw new UnauthorizedAccessException(GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource)
{ {
throw new ObjectDisposedException(objectName, GetResourceString(resource)); throw new ObjectDisposedException(objectName, GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowObjectDisposedException(ExceptionResource resource) internal static void ThrowObjectDisposedException(ExceptionResource resource)
{ {
throw new ObjectDisposedException(null, GetResourceString(resource)); throw new ObjectDisposedException(null, GetResourceString(resource));
} }
[DoesNotReturn]
internal static void ThrowNotSupportedException() internal static void ThrowNotSupportedException()
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
[DoesNotReturn]
internal static void ThrowAggregateException(List<Exception> exceptions) internal static void ThrowAggregateException(List<Exception> exceptions)
{ {
throw new AggregateException(exceptions); throw new AggregateException(exceptions);
} }
[DoesNotReturn]
internal static void ThrowOutOfMemoryException() internal static void ThrowOutOfMemoryException()
{ {
throw new OutOfMemoryException(); throw new OutOfMemoryException();
} }
[DoesNotReturn]
internal static void ThrowArgumentException_Argument_InvalidArrayType() internal static void ThrowArgumentException_Argument_InvalidArrayType()
{ {
throw new ArgumentException("Invalid array type."); throw new ArgumentException("Invalid array type.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted() internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted()
{ {
throw new InvalidOperationException("Enumeration has not started."); throw new InvalidOperationException("Enumeration has not started.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded() internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded()
{ {
throw new InvalidOperationException("Enumeration has ended."); throw new InvalidOperationException("Enumeration has ended.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_EnumCurrent(int index) internal static void ThrowInvalidOperationException_EnumCurrent(int index)
{ {
throw GetInvalidOperationException_EnumCurrent(index); throw GetInvalidOperationException_EnumCurrent(index);
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
{ {
throw new InvalidOperationException("Collection was modified during enumeration."); throw new InvalidOperationException("Collection was modified during enumeration.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
{ {
throw new InvalidOperationException("Invalid enumerator state: enumeration cannot proceed."); throw new InvalidOperationException("Invalid enumerator state: enumeration cannot proceed.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_InvalidOperation_NoValue() internal static void ThrowInvalidOperationException_InvalidOperation_NoValue()
{ {
throw new InvalidOperationException("No value provided."); throw new InvalidOperationException("No value provided.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported() internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported()
{ {
throw new InvalidOperationException("Concurrent operations are not supported."); throw new InvalidOperationException("Concurrent operations are not supported.");
} }
[DoesNotReturn]
internal static void ThrowInvalidOperationException_HandleIsNotInitialized() internal static void ThrowInvalidOperationException_HandleIsNotInitialized()
{ {
throw new InvalidOperationException("Handle is not initialized."); throw new InvalidOperationException("Handle is not initialized.");
} }
[DoesNotReturn]
internal static void ThrowFormatException_BadFormatSpecifier() internal static void ThrowFormatException_BadFormatSpecifier()
{ {
throw new FormatException("Bad format specifier."); throw new FormatException("Bad format specifier.");
@ -300,17 +348,17 @@ namespace Avalonia.Collections.Pooled
return new InvalidOperationException(GetResourceString(resource)); 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)); 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)); 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}"); 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 // 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 // Or just leaves null test and call to the Non-returning ThrowHelper.ThrowArgumentNullException
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) internal static void IfNullAndNullsAreIllegalThenThrow<T>(object? value, ExceptionArgument argName)
{ {
// Note that default(T) is not equal to null for value types except when T is Nullable<U>. // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
if (!(default(T) == null) && value == null) if (!(default(T) == null) && value == null)

3
src/Avalonia.Styling/Controls/ResourceDictionary.cs

@ -68,7 +68,8 @@ namespace Avalonia.Controls
{ {
x.RemoveOwner(Owner); x.RemoveOwner(Owner);
} }
}, null); },
() => throw new NotSupportedException("Dictionary reset not supported"));
} }
return _mergedDictionaries; return _mergedDictionaries;

Loading…
Cancel
Save