Skip to content

Commit

Permalink
Avoid zero-length array allocations (dotnet#19300)
Browse files Browse the repository at this point in the history
* Avoid zero-length array allocations

* Enforce CA1825 solution-wide

---------

Co-authored-by: Jeremy Powell <jeremy@visionaid.com>
  • Loading branch information
molesmoke and jeremy-visionaid authored Jan 16, 2024
1 parent 3890e04 commit 5727faa
Show file tree
Hide file tree
Showing 44 changed files with 68 additions and 63 deletions.
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dotnet_diagnostic.CA1307.severity = error
dotnet_diagnostic.CA1309.severity = error
dotnet_diagnostic.CA1311.severity = error
dotnet_diagnostic.CA1815.severity = error
dotnet_diagnostic.CA1825.severity = error

# nullability checks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ Xamarin.UITest.Queries.AppResult TestForImageVisible()
if (result[0].Rect.Height > 1)
return result;
return new Xamarin.UITest.Queries.AppResult[0];
return Array.Empty<Xamarin.UITest.Queries.AppResult>();
}, 10, 4000);

Assert.AreEqual(1, images.Length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ int[] GetSelectedPositions()
switch (ItemsView.SelectionMode)
{
case SelectionMode.None:
return new int[0];
return Array.Empty<int>();

case SelectionMode.Single:
var selectedItem = ItemsView.SelectedItem;
if (selectedItem == null)
{
return new int[0];
return Array.Empty<int>();
}

return new int[1] { GetPositionForItem(selectedItem) };
Expand All @@ -104,7 +104,7 @@ int[] GetSelectedPositions()
return result;
}

return new int[0];
return Array.Empty<int>();
}

bool PositionIsSelected(int position)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ void OnKeyboardBackPressed(object sender, EventArgs eventArgs)
[PortHandler]
void UpdateMaxLength()
{
var currentFilters = new List<IInputFilter>(EditText?.GetFilters() ?? new IInputFilter[0]);
var currentFilters = new List<IInputFilter>(EditText?.GetFilters() ?? Array.Empty<IInputFilter>());

for (var i = 0; i < currentFilters.Count; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ void OnKeyboardBackPressed(object sender, EventArgs eventArgs)
[PortHandler]
void UpdateMaxLength()
{
var currentFilters = new List<IInputFilter>(EditText?.GetFilters() ?? new IInputFilter[0]);
var currentFilters = new List<IInputFilter>(EditText?.GetFilters() ?? Array.Empty<IInputFilter>());

for (var i = 0; i < currentFilters.Count; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ void UpdateMaxLength()
{
_editText = _editText ?? Control.GetChildrenOfType<AppCompatAutoCompleteTextView>().FirstOrDefault();

var currentFilters = new List<IInputFilter>(_editText?.GetFilters() ?? new IInputFilter[0]);
var currentFilters = new List<IInputFilter>(_editText?.GetFilters() ?? Array.Empty<IInputFilter>());

for (var i = 0; i < currentFilters.Count; i++)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Compatibility/Core/src/Tizen/Forms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static class Forms

public static Size PhysicalScreenSize => DeviceDisplay.MainDisplayInfo.GetScaledScreenSize();

public static IReadOnlyList<string> Flags => s_flags ?? (s_flags = new string[0]);
public static IReadOnlyList<string> Flags => s_flags ?? (s_flags = Array.Empty<string>());

public static IMauiContext MauiContext { get; internal set; }

Expand Down
4 changes: 2 additions & 2 deletions src/Compatibility/Core/src/iOS/DragAndDropDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public UIDragItem[] GetItemsForBeginningSession(UIDragInteraction interaction, I
if (interaction.View is IVisualElementRenderer renderer && renderer.Element is View view)
return HandleDragStarting(view, renderer);

return new UIDragItem[0];
return Array.Empty<UIDragItem>();
}

[Export("dropInteraction:canHandleSession:")]
Expand Down Expand Up @@ -193,7 +193,7 @@ public UIDragItem[] HandleDragStarting(View element, IVisualElementRenderer rend
},
element);

return returnValue ?? new UIDragItem[0];
return returnValue ?? Array.Empty<UIDragItem>();
}

void HandleDropCompleted(View element)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static class DoubleCollectionExtensions
public static nfloat[] ToArray(this DoubleCollection doubleCollection)
{
if (doubleCollection == null || doubleCollection.Count == 0)
return new nfloat[0];
return Array.Empty<nfloat>();
else
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static CGPoint[] ToCGPoints(this PointCollection pointCollection)
{
if (pointCollection == null || pointCollection.Count == 0)
{
return new CGPoint[0];
return System.Array.Empty<CGPoint>();
}

CGPoint[] points = new CGPoint[pointCollection.Count];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1422,8 +1422,8 @@ void UpdateToolbarItems()

if (primaries != null)
primaries.Reverse();
NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
ToolbarItems = secondaries == null ? new UIBarButtonItem[0] : secondaries.ToArray();
NavigationItem.SetRightBarButtonItems(primaries == null ? Array.Empty<UIBarButtonItem>() : primaries.ToArray(), false);
ToolbarItems = secondaries == null ? Array.Empty<UIBarButtonItem>() : secondaries.ToArray();

NavigationRenderer n;
if (_navigation.TryGetTarget(out n))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ async Task<List<NSHttpCookie>> GetCookiesFromNativeStore(string url)
}
}

_initialCookiesLoaded = _initialCookiesLoaded ?? new NSHttpCookie[0];
_initialCookiesLoaded = _initialCookiesLoaded ?? Array.Empty<NSHttpCookie>();

List<NSHttpCookie> existingCookies = new List<NSHttpCookie>();
string domain = CreateUriForCookies(url).Host;
Expand Down
2 changes: 1 addition & 1 deletion src/Compatibility/Core/src/iOS/Shapes/ShapeRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void UpdateStrokeThickness()
void UpdateStrokeDashArray()
{
if (Element.StrokeDashArray == null || Element.StrokeDashArray.Count == 0)
Control.ShapeLayer.UpdateStrokeDash(new nfloat[0]);
Control.ShapeLayer.UpdateStrokeDash(Array.Empty<nfloat>());
else
{
nfloat[] dashArray;
Expand Down
6 changes: 3 additions & 3 deletions src/Controls/Foldable/src/DualScreenInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public DualScreenInfo(VisualElement element) : this(element, null)

internal DualScreenInfo(VisualElement element, IFoldableService dualScreenService)
{
_spanningBounds = new Rect[0];
_spanningBounds = Array.Empty<Rect>();
Element = element;
_dualScreenService = dualScreenService;

Expand Down Expand Up @@ -179,10 +179,10 @@ Rect[] GetSpanningBounds()
var hinge = guide.Hinge;

if (hinge == Rect.Zero)
return new Rect[0];
return Array.Empty<Rect>();

if (guide.Pane2 == Rect.Zero)
return new Rect[0];
return Array.Empty<Rect>();

//TODO: I think this should this be checking SpanMode==Wide
if (IsLandscape)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ protected virtual bool ParseIndexes(out int[] indexes)
{
if (!int.TryParse(Entry.Text, out int index))
{
indexes = new int[0];
indexes = Array.Empty<int>();
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1531,8 +1531,8 @@ void UpdateToolbarItems()

if (primaries != null)
primaries.Reverse();
NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
ToolbarItems = secondaries == null ? new UIBarButtonItem[0] : secondaries.ToArray();
NavigationItem.SetRightBarButtonItems(primaries == null ? Array.Empty<UIBarButtonItem>() : primaries.ToArray(), false);
ToolbarItems = secondaries == null ? Array.Empty<UIBarButtonItem>() : secondaries.ToArray();

NavigationRenderer n;
if (_navigation.TryGetTarget(out n))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Microsoft.Maui.Controls.Platform.Compatibility
{
public class ShellItemRenderer : UITabBarController, IShellItemRenderer, IAppearanceObserver, IUINavigationControllerDelegate, IDisconnectable
{
readonly static UITableViewCell[] EmptyUITableViewCellArray = Array.Empty<UITableViewCell>();

#region IShellItemRenderer

public ShellItem ShellItem
Expand Down Expand Up @@ -346,7 +348,7 @@ UITableViewCell[] GetMoreNavigationCells()
if (MoreNavigationController.TopViewController.View is UITableView uITableView)
return uITableView.VisibleCells;

return new UITableViewCell[0];
return EmptyUITableViewCellArray;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ protected virtual void UpdateToolbarItems()
primaries.Reverse();
}

NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
NavigationItem.SetRightBarButtonItems(primaries == null ? Array.Empty<UIBarButtonItem>() : primaries.ToArray(), false);

UpdateLeftToolbarItems();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ int[] GetSelectedPositions()
switch (ItemsView.SelectionMode)
{
case SelectionMode.None:
return new int[0];
return Array.Empty<int>();

case SelectionMode.Single:
var selectedItem = ItemsView.SelectedItem;
if (selectedItem == null)
{
return new int[0];
return Array.Empty<int>();
}

return new int[1] { GetPositionForItem(selectedItem) };
Expand All @@ -104,7 +104,7 @@ int[] GetSelectedPositions()
return result;
}

return new int[0];
return Array.Empty<int>();
}

bool PositionIsSelected(int position)
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/src/Core/LegacyLayouts/ConstraintExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public Constraint ProvideValue(IServiceProvider serviceProvider)
if (string.IsNullOrEmpty(Property))
return null;
minfo = typeof(View).GetProperties().First(pi => pi.Name == Property && pi.CanRead && pi.GetMethod.IsPublic).GetMethod;
return Constraint.RelativeToParent(p => (double)minfo.Invoke(p, new object[] { }) * Factor + Constant);
return Constraint.RelativeToParent(p => (double)minfo.Invoke(p, Array.Empty<object>()) * Factor + Constant);
case ConstraintType.Constant:
return Constraint.Constant(Constant);
case ConstraintType.RelativeToView:
Expand All @@ -62,7 +62,7 @@ public Constraint ProvideValue(IServiceProvider serviceProvider)
view = ((INameScope)valueProvider.TargetObject).FindByName<View>(ElementName);
}
return Constraint.RelativeToView(view, delegate (RelativeLayout p, View v)
{ return (double)minfo.Invoke(v, new object[] { }) * Factor + Constant; });
{ return (double)minfo.Invoke(v, Array.Empty<object>()) * Factor + Constant; });
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Core/Menu/MenuItemTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public IList<TMenuItem> ToolbarItems
get
{
if (Target == null)
return new TMenuItem[0];
return Array.Empty<TMenuItem>();

// I realize this is sorting on every single get but we don't have
// a mechanism in place currently to invalidate a stored version of this
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Core/Platform/iOS/DragAndDropDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public UIDragItem[] HandleDragStarting(View element, IPlatformViewHandler handle
},
element);

return returnValue ?? new UIDragItem[0];
return returnValue ?? Array.Empty<UIDragItem>();
}

void SetLocalObject(UIDragItem dragItem, IPlatformViewHandler handler, DataPackage data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using CoreAnimation;
Expand Down Expand Up @@ -222,7 +223,7 @@ static CGPoint GetRadialGradientBrushEndPoint(Point startPoint, double radius)
static NSNumber[] GetCAGradientLayerLocations(List<GradientStop> gradientStops)
{
if (gradientStops == null || gradientStops.Count == 0)
return new NSNumber[0];
return Array.Empty<NSNumber>();

if (gradientStops.Count > 1 && gradientStops.Any(gt => gt.Offset != 0))
return gradientStops.Select(x => new NSNumber(x.Offset)).ToArray();
Expand Down Expand Up @@ -254,7 +255,7 @@ static NSNumber[] GetCAGradientLayerLocations(List<GradientStop> gradientStops)
static CGColor[] GetCAGradientLayerColors(List<GradientStop> gradientStops)
{
if (gradientStops == null || gradientStops.Count == 0)
return new CGColor[0];
return Array.Empty<CGColor>();

CGColor[] colors = new CGColor[gradientStops.Count];

Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Core/PlatformBindingHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static void SetValueFromNative<TPlatformView>(TPlatformView target, string targe
BindableObjectProxy<TPlatformView> proxy;
if (!BindableObjectProxy<TPlatformView>.BindableObjectProxies.TryGetValue(target, out proxy))
return;
SetValueFromRenderer(proxy, bindableProperty, target.GetType().GetProperty(targetProperty)?.GetMethod.Invoke(target, new object[] { }));
SetValueFromRenderer(proxy, bindableProperty, target.GetType().GetProperty(targetProperty)?.GetMethod.Invoke(target, Array.Empty<object>()));
}

static void SetValueFromRenderer(BindableObject bindable, BindableProperty property, object value)
Expand Down
6 changes: 3 additions & 3 deletions src/Controls/src/Core/TemplatedItemsList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ internal TemplatedItemsList(TView itemsView, BindableProperty itemSourceProperty
if (source != null)
ListProxy = new ListProxy(source, dispatcher: _itemsView.Dispatcher);
else
ListProxy = new ListProxy(new object[0], dispatcher: _itemsView.Dispatcher);
ListProxy = new ListProxy(Array.Empty<object>(), dispatcher: _itemsView.Dispatcher);
}

internal TemplatedItemsList(TemplatedItemsList<TView, TItem> parent, IEnumerable itemSource, TView itemsView, BindableProperty itemTemplateProperty, int windowSize = int.MaxValue)
Expand All @@ -91,7 +91,7 @@ internal TemplatedItemsList(TemplatedItemsList<TView, TItem> parent, IEnumerable
ListProxy.CollectionChanged += OnProxyCollectionChanged;
}
else
ListProxy = new ListProxy(new object[0], dispatcher: _itemsView.Dispatcher);
ListProxy = new ListProxy(Array.Empty<object>(), dispatcher: _itemsView.Dispatcher);
}

event PropertyChangedEventHandler ITemplatedItemsList<TItem>.PropertyChanged
Expand Down Expand Up @@ -944,7 +944,7 @@ void OnItemsSourceChanged(bool fromGrouping = false)

IEnumerable itemSource = GetItemsViewSource();
if (itemSource == null)
ListProxy = new ListProxy(new object[0], dispatcher: _itemsView.Dispatcher);
ListProxy = new ListProxy(Array.Empty<object>(), dispatcher: _itemsView.Dispatcher);
else
ListProxy = new ListProxy(itemSource, dispatcher: _itemsView.Dispatcher);

Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Xaml/ApplyPropertiesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ static bool TryGetProperty(object element, string localName, out object value, I
if (!IsVisibleFrom(getter, rootElement))
return false;

value = getter.Invoke(element, new object[] { });
value = getter.Invoke(element, Array.Empty<object>());
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Xaml/CreateValuesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public object CreateFromFactory(Type nodeType, IElementNode node)
}

var factoryMethod = ((string)((ValueNode)node.Properties[XmlName.xFactoryMethod]).Value);
Type[] types = arguments == null ? new Type[0] : arguments.Select(a => a.GetType()).ToArray();
Type[] types = arguments == null ? Array.Empty<Type>() : arguments.Select(a => a.GetType()).ToArray();

bool isMatch(MethodInfo m)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Xaml/MarkupExtensions/StaticExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public object ProvideValue(IServiceProvider serviceProvider)

var pinfo = type.GetRuntimeProperties().FirstOrDefault(pi => pi.Name == membername && pi.GetMethod.IsStatic);
if (pinfo != null)
return pinfo.GetMethod.Invoke(null, new object[] { });
return pinfo.GetMethod.Invoke(null, Array.Empty<object>());

var finfo = type.GetRuntimeFields().FirstOrDefault(fi => fi.Name == membername && fi.IsStatic);
if (finfo != null)
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/Core.UnitTests/BindableLayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ public void ValidateBindableProperties()


// ItemsSourceProperty
IEnumerable itemsSource = new object[0];
IEnumerable itemsSource = Array.Empty<object>();
BindableLayout.SetItemsSource(layout, itemsSource);

Assert.Equal(itemsSource, BindableLayout.GetItemsSource(layout));
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/tests/Core.UnitTests/BindingBaseUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -696,9 +696,9 @@ public void EnableCollectionSynchronizationInvalid()
{
Assert.Throws<ArgumentNullException>(() => BindingBase.EnableCollectionSynchronization(null, new object(),
(collection, context, method, access) => { }));
Assert.Throws<ArgumentNullException>(() => BindingBase.EnableCollectionSynchronization(new string[0], new object(), null));
Assert.Throws<ArgumentNullException>(() => BindingBase.EnableCollectionSynchronization(Array.Empty<string>(), new object(), null));

BindingBase.EnableCollectionSynchronization(new string[0], null, (collection, context, method, access) => { });
BindingBase.EnableCollectionSynchronization(Array.Empty<string>(), null, (collection, context, method, access) => { });
}

[Fact]
Expand Down
Loading

0 comments on commit 5727faa

Please sign in to comment.