Enable nullable reference types

Closes #36
This commit is contained in:
Patrik Svensson 2020-08-11 17:15:58 +02:00 committed by Patrik Svensson
parent a273f74758
commit 5d132220ba
25 changed files with 98 additions and 72 deletions

View File

@ -77,4 +77,7 @@ dotnet_diagnostic.CA1032.severity = none
dotnet_diagnostic.CA1826.severity = none
# RCS1079: Throwing of new NotImplementedException.
dotnet_diagnostic.RCS1079.severity = warning
dotnet_diagnostic.RCS1079.severity = warning
# RCS1057: Add empty line between declarations.
dotnet_diagnostic.RCS1057.severity = none

View File

@ -34,7 +34,7 @@
<ItemGroup Label="Package References">
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -7,11 +7,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="Shouldly" Version="4.0.0-beta0002" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@ -21,6 +21,6 @@ namespace Spectre.Console
/// <summary>
/// Gets or sets the out buffer.
/// </summary>
public TextWriter Out { get; set; }
public TextWriter? Out { get; set; }
}
}

View File

@ -50,7 +50,7 @@ namespace Spectre.Console
ColorSystem.Standard => "4 bits",
ColorSystem.EightBit => "8 bits",
ColorSystem.TrueColor => "24 bits",
_ => "?"
_ => "?",
};
return $"ANSI={supportsAnsi}, Colors={ColorSystem}, Kind={legacyConsole} ({bits})";

View File

@ -74,7 +74,7 @@ namespace Spectre.Console
}
/// <inheritdoc/>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Color color && Equals(color);
}

View File

@ -57,15 +57,20 @@ namespace Spectre.Console.Composition
private Dictionary<BorderPart, string> Initialize()
{
var lookup = new Dictionary<BorderPart, string>();
foreach (BorderPart part in Enum.GetValues(typeof(BorderPart)))
foreach (BorderPart? part in Enum.GetValues(typeof(BorderPart)))
{
var text = GetBoxPart(part);
if (part == null)
{
continue;
}
var text = GetBoxPart(part.Value);
if (text.Length > 1)
{
throw new InvalidOperationException("A box part cannot contain more than one character.");
}
lookup.Add(part, GetBoxPart(part));
lookup.Add(part.Value, GetBoxPart(part.Value));
}
return lookup;

View File

@ -9,22 +9,22 @@ namespace Spectre.Console
/// Gets or sets the width of the column.
/// If <c>null</c>, the column will adapt to it's contents.
/// </summary>
public int? Width { get; set; } = null;
public int? Width { get; set; }
/// <summary>
/// Gets or sets a value indicating whether wrapping of
/// text within the column should be prevented.
/// </summary>
public bool NoWrap { get; set; } = false;
public bool NoWrap { get; set; }
/// <summary>
/// Gets or sets the padding of the column.
/// </summary>
public Padding? Padding { get; set; } = null;
public Padding? Padding { get; set; }
/// <summary>
/// Gets or sets the alignment of the column.
/// </summary>
public Justify? Alignment { get; set; } = null;
public Justify? Alignment { get; set; }
}
}

View File

@ -16,7 +16,7 @@ namespace Spectre.Console
Right = 1,
/// <summary>
/// Centered
/// Centered.
/// </summary>
Center = 2,
}

View File

@ -29,7 +29,7 @@ namespace Spectre.Console.Composition
}
/// <inheritdoc/>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Measurement measurement && Equals(measurement);
}

View File

@ -29,7 +29,7 @@ namespace Spectre.Console
}
/// <inheritdoc/>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Padding padding && Equals(padding);
}

View File

@ -9,6 +9,8 @@ namespace Spectre.Console
/// </summary>
public sealed class Panel : IRenderable
{
private const int EdgeWidth = 2;
private readonly IRenderable _child;
/// <summary>
@ -26,14 +28,14 @@ namespace Spectre.Console
/// <summary>
/// Gets or sets the alignment of the panel contents.
/// </summary>
public Justify? Alignment { get; set; } = null;
public Justify? Alignment { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not the panel should
/// fit the available space. If <c>false</c>, the panel width will be
/// auto calculated. Defaults to <c>false</c>.
/// </summary>
public bool Expand { get; set; } = false;
public bool Expand { get; set; }
/// <summary>
/// Gets or sets the padding.
@ -61,13 +63,12 @@ namespace Spectre.Console
{
var border = Composition.Border.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
var edgeWidth = 2;
var paddingWidth = Padding.GetHorizontalPadding();
var childWidth = width - edgeWidth - paddingWidth;
var childWidth = width - EdgeWidth - paddingWidth;
if (!Expand)
{
var measurement = _child.Measure(context, width - edgeWidth - paddingWidth);
var measurement = _child.Measure(context, width - EdgeWidth - paddingWidth);
childWidth = measurement.Max;
}

View File

@ -50,7 +50,12 @@ namespace Spectre.Console.Composition
private Segment(string text, Style style, bool lineBreak)
{
Text = text?.NormalizeLineEndings() ?? throw new ArgumentNullException(nameof(text));
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
Text = text.NormalizeLineEndings();
Style = style;
IsLineBreak = lineBreak;
}
@ -89,7 +94,7 @@ namespace Spectre.Console.Composition
/// </summary>
/// <param name="offset">The offset where to split the segment.</param>
/// <returns>One or two new segments representing the split.</returns>
public (Segment First, Segment Second) Split(int offset)
public (Segment First, Segment? Second) Split(int offset)
{
if (offset < 0)
{

View File

@ -11,6 +11,8 @@ namespace Spectre.Console
/// </summary>
public sealed partial class Table
{
private const int EdgeCount = 2;
// Calculate the widths of each column, including padding, not including borders.
// Ported from Rich by Will McGugan, licensed under MIT.
// https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/table.py#L394
@ -115,10 +117,9 @@ namespace Spectre.Console
private int GetExtraWidth(bool includePadding)
{
var edges = 2;
var separators = _columns.Count - 1;
var padding = includePadding ? _columns.Select(x => x.Padding.GetHorizontalPadding()).Sum() : 0;
return separators + edges + padding;
return separators + EdgeCount + padding;
}
}
}

View File

@ -39,12 +39,12 @@ namespace Spectre.Console
/// fit the available space. If <c>false</c>, the table width will be
/// auto calculated. Defaults to <c>false</c>.
/// </summary>
public bool Expand { get; set; } = false;
public bool Expand { get; set; }
/// <summary>
/// Gets or sets the width of the table.
/// </summary>
public int? Width { get; set; } = null;
public int? Width { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not to use
@ -54,7 +54,7 @@ namespace Spectre.Console
public bool SafeBorder { get; set; } = true;
// Whether this is a grid or not.
internal bool IsGrid { get; set; } = false;
internal bool IsGrid { get; set; }
// Whether or not the most right cell should be padded.
// This is almost always the case, unless we're rendering

View File

@ -201,7 +201,7 @@ namespace Spectre.Console
return result;
}
private IEnumerable<Segment> SplitLineBreaks(IEnumerable<Segment> segments)
private static IEnumerable<Segment> SplitLineBreaks(IEnumerable<Segment> segments)
{
// Creates individual segments of line breaks.
var result = new List<Segment>();
@ -228,7 +228,11 @@ namespace Spectre.Console
}
result.Add(Segment.LineBreak());
queue.Push(new Segment(second.Text.Substring(1), second.Style));
if (second != null)
{
queue.Push(new Segment(second.Text.Substring(1), second.Style));
}
}
}

View File

@ -45,7 +45,7 @@ namespace Spectre.Console.Internal
return ColorPalette.EightBit[number];
}
public static string GetName(int number)
public static string? GetName(int number)
{
_nameLookup.TryGetValue(number, out var name);
return name;

View File

@ -17,14 +17,9 @@ namespace Spectre.Console.Internal
public static string NormalizeLineEndings(this string text, bool native = false)
{
if (text == null)
{
return null;
}
var normalized = text?.Replace("\r\n", "\n")
?.Replace("\r", string.Empty);
text ??= string.Empty;
var normalized = text?.Replace("\r\n", "\n")?.Replace("\r", string.Empty) ?? string.Empty;
if (native && !_alreadyNormalized)
{
normalized = normalized.Replace("\n", Environment.NewLine);
@ -35,7 +30,8 @@ namespace Spectre.Console.Internal
public static string[] SplitLines(this string text)
{
return text.NormalizeLineEndings().Split(new[] { '\n' }, StringSplitOptions.None);
var result = text?.NormalizeLineEndings()?.Split(new[] { '\n' }, StringSplitOptions.None);
return result ?? Array.Empty<string>();
}
}
}

View File

@ -6,7 +6,7 @@ namespace Spectre.Console.Internal
{
internal static class MarkupParser
{
public static Text Parse(string text, Style style = null)
public static Text Parse(string text, Style? style = null)
{
style ??= Style.Plain;
@ -18,6 +18,10 @@ namespace Spectre.Console.Internal
while (tokenizer.MoveNext())
{
var token = tokenizer.Current;
if (token == null)
{
break;
}
if (token.Kind == MarkupTokenKind.Open)
{

View File

@ -7,7 +7,7 @@ namespace Spectre.Console.Internal
{
private readonly StringBuffer _reader;
public MarkupToken Current { get; private set; }
public MarkupToken? Current { get; private set; }
public MarkupTokenizer(string text)
{

View File

@ -1,10 +1,12 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace Spectre.Console.Internal
{
internal sealed class StringBuffer : IDisposable
{
[SuppressMessage("Usage", "CA2213:Disposable fields should be disposed", Justification = "False positive")]
private readonly StringReader _reader;
private readonly int _length;

View File

@ -14,16 +14,23 @@ namespace Spectre.Console.Internal
throw new InvalidOperationException(error);
}
if (style == null)
{
// This should not happen, but we need to please the compiler
// which cannot know that style isn't null here.
throw new InvalidOperationException("Could not parse style.");
}
return style;
}
public static bool TryParse(string text, out Style style)
public static bool TryParse(string text, out Style? style)
{
style = Parse(text, out var error);
return error == null;
}
private static Style Parse(string text, out string error)
private static Style? Parse(string text, out string? error)
{
var effectiveDecoration = (Decoration?)null;
var effectiveForeground = (Color?)null;
@ -113,11 +120,11 @@ namespace Spectre.Console.Internal
}
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
private static Color? ParseHexColor(string hex, out string error)
private static Color? ParseHexColor(string hex, out string? error)
{
error = null;
hex = hex ?? string.Empty;
hex ??= string.Empty;
hex = hex.Replace("#", string.Empty).Trim();
try
@ -151,11 +158,12 @@ namespace Spectre.Console.Internal
}
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
private static Color? ParseRgbColor(string rgb, out string error)
private static Color? ParseRgbColor(string rgb, out string? error)
{
try
{
error = null;
var normalized = rgb ?? string.Empty;
if (normalized.Length >= 3)
{

View File

@ -40,7 +40,7 @@ namespace Spectre.Console.Internal
return result;
}
public static List<int> Distribute(int total, List<int> ratios, List<int> minimums = null)
public static List<int> Distribute(int total, List<int> ratios, List<int>? minimums = null)
{
if (minimums != null)
{

View File

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
@ -9,27 +10,21 @@
<None Include="../../gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
</ItemGroup>
<ItemGroup>
<Compile Update="**/ColorPalette.*.cs">
<DependentUpon>**/ColorPalette.cs</DependentUpon>
</Compile>
<Compile Update="Color.*.cs">
<DependentUpon>Color.cs</DependentUpon>
</Compile>
<Compile Update="AnsiConsole.*.cs">
<DependentUpon>AnsiConsole.cs</DependentUpon>
</Compile>
<Compile Update="ConsoleExtensions.*.cs">
<DependentUpon>ConsoleExtensions.cs</DependentUpon>
</Compile>
<Compile Update="**/Table.*.cs">
<DependentUpon>**/Table.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="1.0.0-alpha.160" PrivateAssets="all" />
<PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]" />
<PackageReference Include="Nullable" Version="1.2.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<AnnotatedReferenceAssemblyVersion>3.0.0</AnnotatedReferenceAssemblyVersion>
<GenerateNullableAttributes>False</GenerateNullableAttributes>
</PropertyGroup>
</Project>

View File

@ -67,7 +67,7 @@ namespace Spectre.Console
/// if the conversion succeeded, or <c>null</c> if the conversion failed.
/// </param>
/// <returns><c>true</c> if s was converted successfully; otherwise, <c>false</c>.</returns>
public static bool TryParse(string text, out Style result)
public static bool TryParse(string text, out Style? result)
{
return StyleParser.TryParse(text, out result);
}
@ -113,13 +113,13 @@ namespace Spectre.Console
}
/// <inheritdoc/>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return Equals(obj as Style);
}
/// <inheritdoc/>
public bool Equals(Style other)
public bool Equals(Style? other)
{
if (other == null)
{