Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable nullable on Avalonia.Diagnostics project #5998

Merged
merged 6 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 79 additions & 2 deletions src/Avalonia.Base/Metadata/NullableAttributes.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma warning disable MA0048 // File name must match type name
#define INTERNAL_NULLABLE_ATTRIBUTES
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48

// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs

Expand All @@ -10,6 +9,7 @@

namespace System.Diagnostics.CodeAnalysis
{
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
Expand Down Expand Up @@ -136,5 +136,82 @@ sealed class DoesNotReturnIfAttribute : Attribute
/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}
}
#endif // NETSTANDARD2_0 attributes

#if NETSTANDARD2_1 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48
/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// not-<see langword="null"/> values.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MemberNotNullAttribute : Attribute
{
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }

/// <summary>Initializes the attribute with a field or property member.</summary>
/// <param name="member">The field or property member that is promised to be not-null.</param>
public MemberNotNullAttribute(string member)
{
Members = new[] { member };
}

/// <summary>Initializes the attribute with the list of field and property members.</summary>
/// <param name="members">The list of field and property members that are promised to be not-null.</param>
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}

/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// non-<see langword="null"/> values when returning with the specified return value condition.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }

/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }

/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value,
/// the associated parameter will not be <see langword="null"/>.
/// </param>
/// <param name="member">The field or property member that is promised to be not-<see langword="null"/>.</param>
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}

/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.
/// </summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value,
/// the associated parameter will not be <see langword="null"/>.
/// </param>
/// <param name="members">The list of field and property members that are promised to be not-null.</param>
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
#endif // NETSTANDARD2_1 attributes
}

4 changes: 4 additions & 0 deletions src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Avalonia</RootNamespace>
<PackageId>Avalonia.Diagnostics</PackageId>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ internal class ThicknessEditor : ContentControl
AvaloniaProperty.RegisterDirect<ThicknessEditor, Thickness>(nameof(Thickness), o => o.Thickness,
(o, v) => o.Thickness = v, defaultBindingMode: BindingMode.TwoWay);

public static readonly DirectProperty<ThicknessEditor, string> HeaderProperty =
AvaloniaProperty.RegisterDirect<ThicknessEditor, string>(nameof(Header), o => o.Header,
public static readonly DirectProperty<ThicknessEditor, string?> HeaderProperty =
AvaloniaProperty.RegisterDirect<ThicknessEditor, string?>(nameof(Header), o => o.Header,
(o, v) => o.Header = v);

public static readonly DirectProperty<ThicknessEditor, bool> IsPresentProperty =
Expand All @@ -36,7 +36,7 @@ internal class ThicknessEditor : ContentControl
AvaloniaProperty.Register<ThicknessEditor, IBrush>(nameof(Highlight));

private Thickness _thickness;
private string _header;
private string? _header;
private bool _isPresent = true;
private double _left;
private double _top;
Expand All @@ -50,7 +50,7 @@ public Thickness Thickness
set => SetAndRaise(ThicknessProperty, ref _thickness, value);
}

public string Header
public string? Header
{
get => _header;
set => SetAndRaise(HeaderProperty, ref _header, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@ internal class BoolToOpacityConverter : IValueConverter
{
public double Opacity { get; set; }

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return (bool)value ? 1d : Opacity;
if (value is bool boolean && boolean)
{
return 1d;
}

return Opacity;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Avalonia.Diagnostics.Converters
{
internal class EnumToCheckedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return Equals(value, parameter);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is bool isChecked && isChecked)
{
Expand Down
10 changes: 4 additions & 6 deletions src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using Avalonia.Input;
using Avalonia.Interactivity;

#nullable enable

namespace Avalonia.Diagnostics
{
public static class DevTools
Expand All @@ -24,7 +22,7 @@ public static IDisposable Attach(TopLevel root, KeyGesture gesture)

public static IDisposable Attach(TopLevel root, DevToolsOptions options)
{
void PreviewKeyDown(object sender, KeyEventArgs e)
void PreviewKeyDown(object? sender, KeyEventArgs e)
{
if (options.Gesture.Matches(e))
{
Expand Down Expand Up @@ -71,10 +69,10 @@ public static IDisposable Open(TopLevel root, DevToolsOptions options)
return Disposable.Create(() => window?.Close());
}

private static void DevToolsClosed(object sender, EventArgs e)
private static void DevToolsClosed(object? sender, EventArgs e)
{
var window = (MainWindow)sender;
s_open.Remove(window.Root);
var window = (MainWindow)sender!;
s_open.Remove(window.Root!);
window.Closed -= DevToolsClosed;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Diagnostics/Diagnostics/Models/ConsoleContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class ConsoleContext
clear(): Clear the output history
";

public dynamic e { get; internal set; }
public dynamic root { get; internal set; }
public dynamic? e { get; internal set; }
public dynamic? root { get; internal set; }

internal static object NoOutput { get; } = new object();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ internal class EventChainLink
{
public EventChainLink(object handler, bool handled, RoutingStrategies route)
{
Contract.Requires<ArgumentNullException>(handler != null);

Handler = handler;
Handler = handler ?? throw new ArgumentNullException(nameof(handler));
Handled = handled;
Route = route;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Diagnostics/Diagnostics/ViewLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ internal class ViewLocator : IDataTemplate
{
public IControl Build(object data)
{
var name = data.GetType().FullName.Replace("ViewModel", "View");
var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);

if (type != null)
{
return (Control)Activator.CreateInstance(type);
return (Control)Activator.CreateInstance(type)!;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using System.ComponentModel;
using Avalonia.Collections;

namespace Avalonia.Diagnostics.ViewModels
{
internal class AvaloniaPropertyViewModel : PropertyViewModel
{
private readonly AvaloniaObject _target;
private string _type;
private object _value;
private object? _value;
private string _priority;
private string _group;

#nullable disable
// Remove "nullable disable" after MemberNotNull will work on our CI.
public AvaloniaPropertyViewModel(AvaloniaObject o, AvaloniaProperty property)
#nullable restore
{
_target = o;
Property = property;
Expand All @@ -20,12 +20,6 @@ public AvaloniaPropertyViewModel(AvaloniaObject o, AvaloniaProperty property)
$"[{property.OwnerType.Name}.{property.Name}]" :
property.Name;

if (property.IsDirect)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to Update to simplify code a bit

{
_group = "Properties";
Priority = "Direct";
}

Update();
}

Expand All @@ -34,11 +28,7 @@ public AvaloniaPropertyViewModel(AvaloniaObject o, AvaloniaProperty property)
public override string Name { get; }
public bool IsAttached => Property.IsAttached;

public string Priority
{
get => _priority;
private set => RaiseAndSetIfChanged(ref _priority, value);
}
public string Priority => _priority;

public override string Type => _type;

Expand All @@ -56,40 +46,37 @@ public override string Value
}
}

public override string Group
{
get => _group;
}
public override string Group => _group;

// [MemberNotNull(nameof(_type), nameof(_group), nameof(_priority))]
public override void Update()
{
if (Property.IsDirect)
{
RaiseAndSetIfChanged(ref _value, _target.GetValue(Property), nameof(Value));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name, nameof(Type));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type));
RaiseAndSetIfChanged(ref _priority, "Direct", nameof(Priority));

_group = "Properties";
}
else
{
var val = _target.GetDiagnostic(Property);

RaiseAndSetIfChanged(ref _value, val?.Value, nameof(Value));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name, nameof(Type));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type));

if (val != null)
{
SetGroup(IsAttached ? "Attached Properties" : "Properties");
Priority = val.Priority.ToString();
RaiseAndSetIfChanged(ref _priority, val.Priority.ToString(), nameof(Priority));
RaiseAndSetIfChanged(ref _group, IsAttached ? "Attached Properties" : "Properties", nameof(Group));
}
else
{
SetGroup(Priority = "Unset");
RaiseAndSetIfChanged(ref _priority, "Unset", nameof(Priority));
RaiseAndSetIfChanged(ref _group, "Unset", nameof(Group));
}
}
}

private void SetGroup(string group)
{
RaiseAndSetIfChanged(ref _group, group, nameof(Group));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
using System.ComponentModel;
using System.Reflection;
using System.Reflection;

namespace Avalonia.Diagnostics.ViewModels
{
internal class ClrPropertyViewModel : PropertyViewModel
{
private readonly object _target;
private string _type;
private object _value;
private object? _value;

#nullable disable
// Remove "nullable disable" after MemberNotNull will work on our CI.
public ClrPropertyViewModel(object o, PropertyInfo property)
#nullable restore
{
_target = o;
Property = property;

if (!property.DeclaringType.IsInterface)
if (property.DeclaringType == null || !property.DeclaringType.IsInterface)
{
Name = property.Name;
}
Expand Down Expand Up @@ -47,11 +49,12 @@ public override string Value
}
}

// [MemberNotNull(nameof(_type))]
public override void Update()
{
var val = Property.GetValue(_target);
RaiseAndSetIfChanged(ref _value, val, nameof(Value));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name, nameof(Type));
RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type));
}
}
}
Loading