From 39c05f34d1468cdff647e375aeae0ccbb4fcf429 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 9 Mar 2021 16:55:13 -0800 Subject: [PATCH] Enable nullable annotations, round 2 of x --- .../Abbreviations/AbbreviationParser.cs | 8 +- .../MediaLinks/HostProviderBuilder.cs | 54 ++++++----- .../Extensions/MediaLinks/IHostProvider.cs | 7 +- .../ReferralLinks/ReferralLinksExtension.cs | 12 +-- .../SelfPipeline/SelfPipelineExtension.cs | 10 +- .../SmartyPants/HtmlSmartyPantRenderer.cs | 7 +- .../SmartyPants/SmartyPantOptions.cs | 2 + .../SmartyPants/SmartyPantsExtension.cs | 4 +- .../Extensions/Tables/PipeTableParser.cs | 93 +++++++++---------- .../Extensions/Yaml/YamlFrontMatterParser.cs | 2 + src/Markdig/Helpers/CharHelper.cs | 2 + src/Markdig/Helpers/LinkHelper.cs | 2 +- src/Markdig/Helpers/OrderedList.cs | 11 ++- src/Markdig/Markdown.cs | 6 +- src/Markdig/MarkdownExtensions.cs | 4 +- src/Markdig/Parsers/BlockParser.cs | 6 +- src/Markdig/Parsers/BlockProcessor.cs | 28 +++--- src/Markdig/Parsers/FencedBlockParserBase.cs | 27 +++--- src/Markdig/Parsers/FencedCodeBlockParser.cs | 3 +- src/Markdig/Parsers/HeadingBlockParser.cs | 4 +- src/Markdig/Parsers/HtmlBlockParser.cs | 3 +- src/Markdig/Parsers/IAttributesParseable.cs | 4 +- src/Markdig/Parsers/IPostInlineProcessor.cs | 4 +- .../Parsers/IndentedCodeBlockParser.cs | 4 +- src/Markdig/Parsers/InlineParser.cs | 2 + src/Markdig/Parsers/InlineProcessor.cs | 27 +++--- .../Parsers/Inlines/CodeInlineParser.cs | 2 + .../Parsers/Inlines/EmphasisDescriptor.cs | 10 +- .../Parsers/Inlines/EmphasisInlineParser.cs | 22 +++-- .../Parsers/Inlines/HtmlEntityParser.cs | 8 +- .../Parsers/Inlines/LineBreakInlineParser.cs | 2 + .../Parsers/Inlines/LinkInlineParser.cs | 20 ++-- src/Markdig/Parsers/ListBlockParser.cs | 10 +- src/Markdig/Parsers/MarkdownParser.cs | 24 ++--- src/Markdig/Parsers/NumberedListItemParser.cs | 3 +- src/Markdig/Parsers/ParagraphBlockParser.cs | 3 +- src/Markdig/Parsers/ParserBase.cs | 4 +- src/Markdig/Parsers/ParserList.cs | 17 ++-- src/Markdig/Parsers/QuoteBlockParser.cs | 3 +- .../Renderers/MarkdownObjectRenderer.cs | 2 + src/Markdig/Syntax/Inlines/Inline.cs | 12 ++- src/Markdig/Syntax/MarkdownObject.cs | 6 +- 42 files changed, 278 insertions(+), 206 deletions(-) diff --git a/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs b/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs index 5313e32f..c65dea8d 100644 --- a/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs +++ b/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using Markdig.Helpers; @@ -41,7 +43,7 @@ namespace Markdig.Extensions.Abbreviations return BlockState.None; } - if (!LinkHelper.TryParseLabel(ref slice, out string label, out SourceSpan labelSpan)) + if (!LinkHelper.TryParseLabel(ref slice, out string? label, out SourceSpan labelSpan)) { return BlockState.None; } @@ -89,10 +91,10 @@ namespace Markdig.Extensions.Abbreviations inlineProcessor.LiteralInlineParser.PostMatch += (InlineProcessor processor, ref StringSlice slice) => { - var literal = (LiteralInline)processor.Inline; + var literal = (LiteralInline)processor.Inline!; var originalLiteral = literal; - ContainerInline container = null; + ContainerInline? container = null; // This is slow, but we don't have much the choice var content = literal.Content; diff --git a/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs b/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs index 71d99aab..25fcc76c 100644 --- a/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs +++ b/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs @@ -2,9 +2,12 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Markdig.Extensions.MediaLinks @@ -13,12 +16,23 @@ namespace Markdig.Extensions.MediaLinks { private sealed class DelegateProvider : IHostProvider { - public string HostPrefix { get; set; } - public Func Delegate { get; set; } - public bool AllowFullScreen { get; set; } = true; - public string Class { get; set; } + public DelegateProvider(string hostPrefix, Func handler, bool allowFullscreen = true, string? className = null) + { + HostPrefix = hostPrefix; + Delegate = handler; + AllowFullScreen = allowFullscreen; + Class = className; + } - public bool TryHandle(Uri mediaUri, bool isSchemaRelative, out string iframeUrl) + public string HostPrefix { get; } + + public Func Delegate { get; } + + public bool AllowFullScreen { get; } + + public string? Class { get; } + + public bool TryHandle(Uri mediaUri, bool isSchemaRelative, [NotNullWhen(true)] out string? iframeUrl) { if (!mediaUri.Host.StartsWith(HostPrefix, StringComparison.OrdinalIgnoreCase)) { @@ -38,14 +52,14 @@ namespace Markdig.Extensions.MediaLinks /// Should the generated iframe has allowfullscreen attribute. /// "class" attribute of generated iframe. /// A with delegate handler. - public static IHostProvider Create(string hostPrefix, Func handler, bool allowFullScreen = true, string iframeClass = null) + public static IHostProvider Create(string hostPrefix, Func handler, bool allowFullScreen = true, string? iframeClass = null) { if (string.IsNullOrEmpty(hostPrefix)) ThrowHelper.ArgumentException("hostPrefix is null or empty.", nameof(hostPrefix)); if (handler == null) ThrowHelper.ArgumentNullException(nameof(handler)); - return new DelegateProvider { HostPrefix = hostPrefix, Delegate = handler, AllowFullScreen = allowFullScreen, Class = iframeClass }; + return new DelegateProvider(hostPrefix, handler, allowFullScreen, iframeClass); } internal static Dictionary KnownHosts { get; } @@ -67,7 +81,7 @@ namespace Markdig.Extensions.MediaLinks return query.Split(SplitAnd, StringSplitOptions.RemoveEmptyEntries); } - private static string YouTube(Uri uri) + private static string? YouTube(Uri uri) { string uriPath = uri.AbsolutePath; if (string.Equals(uriPath, "/embed", StringComparison.OrdinalIgnoreCase) || uriPath.StartsWith("/embed/", StringComparison.OrdinalIgnoreCase)) @@ -85,7 +99,7 @@ namespace Markdig.Extensions.MediaLinks ); } - private static string YouTubeShortened(Uri uri) + private static string? YouTubeShortened(Uri uri) { return BuildYouTubeIframeUrl( uri.AbsolutePath.Substring(1), @@ -93,7 +107,7 @@ namespace Markdig.Extensions.MediaLinks ); } - private static string BuildYouTubeIframeUrl(string videoId, string startTime) + private static string? BuildYouTubeIframeUrl(string? videoId, string? startTime) { if (string.IsNullOrEmpty(videoId)) { @@ -103,29 +117,25 @@ namespace Markdig.Extensions.MediaLinks return string.IsNullOrEmpty(startTime) ? url : $"{url}?start={startTime}"; } - private static string Vimeo(Uri uri) + private static string? Vimeo(Uri uri) { var items = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped).Split('/'); return items.Length > 0 ? $"https://player.vimeo.com/video/{ items[items.Length - 1] }" : null; } - private static string Odnoklassniki(Uri uri) + private static string? Odnoklassniki(Uri uri) { var items = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped).Split('/'); return items.Length > 0 ? $"https://ok.ru/videoembed/{ items[items.Length - 1] }" : null; } - private static string Yandex(Uri uri) + private static string? Yandex(Uri uri) { - var items = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped).Split('/'); - var albumKeyword - = items.Skip(0).FirstOrDefault(); - var albumId - = items.Skip(1).FirstOrDefault(); - var trackKeyword - = items.Skip(2).FirstOrDefault(); - var trackId - = items.Skip(3).FirstOrDefault(); + string[] items = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped).Split('/'); + string? albumKeyword = items.Skip(0).FirstOrDefault(); + string? albumId = items.Skip(1).FirstOrDefault(); + string? trackKeyword = items.Skip(2).FirstOrDefault(); + string? trackId = items.Skip(3).FirstOrDefault(); if (albumKeyword != "album" || albumId == null || trackKeyword != "track" || trackId == null) { diff --git a/src/Markdig/Extensions/MediaLinks/IHostProvider.cs b/src/Markdig/Extensions/MediaLinks/IHostProvider.cs index 0fc333cc..7e0ad0d1 100644 --- a/src/Markdig/Extensions/MediaLinks/IHostProvider.cs +++ b/src/Markdig/Extensions/MediaLinks/IHostProvider.cs @@ -2,7 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; +using System.Diagnostics.CodeAnalysis; namespace Markdig.Extensions.MediaLinks { @@ -14,7 +17,7 @@ namespace Markdig.Extensions.MediaLinks /// /// "class" attribute of generated iframe. /// - string Class { get; } + string? Class { get; } /// /// Generate url for iframe. @@ -23,7 +26,7 @@ namespace Markdig.Extensions.MediaLinks /// if is a schema relative uri, i.e. uri starts with "//". /// Generated url for iframe. /// - bool TryHandle(Uri mediaUri, bool isSchemaRelative, out string iframeUrl); + bool TryHandle(Uri mediaUri, bool isSchemaRelative, [NotNullWhen(true)] out string? iframeUrl); /// /// Should the generated iframe has allowfullscreen attribute. diff --git a/src/Markdig/Extensions/ReferralLinks/ReferralLinksExtension.cs b/src/Markdig/Extensions/ReferralLinks/ReferralLinksExtension.cs index 2fb5c23b..881039fd 100644 --- a/src/Markdig/Extensions/ReferralLinks/ReferralLinksExtension.cs +++ b/src/Markdig/Extensions/ReferralLinks/ReferralLinksExtension.cs @@ -2,12 +2,12 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. -using Markdig.Renderers; -using Markdig.Renderers.Html.Inlines; -using System; +#nullable enable + using System.Collections.Generic; using System.Linq; -using System.Text; +using Markdig.Renderers; +using Markdig.Renderers.Html.Inlines; namespace Markdig.Extensions.ReferralLinks { @@ -18,7 +18,7 @@ namespace Markdig.Extensions.ReferralLinks Rels = rels?.ToList(); } - public List Rels { get; } + public List? Rels { get; } public void Setup(MarkdownPipelineBuilder pipeline) { @@ -26,7 +26,7 @@ namespace Markdig.Extensions.ReferralLinks public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { - string relString = Rels == null? null : + string? relString = Rels is null ? null : string.Join(" ", Rels.Where(r => !string.IsNullOrEmpty(r))); var linkRenderer = renderer.ObjectRenderers.Find(); diff --git a/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs b/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs index 9e9b5dd3..97a24fb2 100644 --- a/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs +++ b/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using Markdig.Helpers; using Markdig.Renderers; @@ -24,7 +26,7 @@ namespace Markdig.Extensions.SelfPipeline /// The matching start tag. /// The default extensions. /// Tag cannot contain angle brackets - public SelfPipelineExtension(string tag = null, string defaultExtensions = null) + public SelfPipelineExtension(string? tag = null, string? defaultExtensions = null) { tag = tag?.Trim(); tag = string.IsNullOrEmpty(tag) ? DefaultTag : tag; @@ -46,7 +48,7 @@ namespace Markdig.Extensions.SelfPipeline /// /// Gets the default pipeline to configure if no tag was found in the input text. Default is null (core pipeline). /// - public string DefaultExtensions { get; } + public string? DefaultExtensions { get; } /// /// Gets the self pipeline hint tag start that will be matched. @@ -78,7 +80,7 @@ namespace Markdig.Extensions.SelfPipeline if (inputText == null) ThrowHelper.ArgumentNullException(nameof(inputText)); var builder = new MarkdownPipelineBuilder(); - string defaultConfig = DefaultExtensions; + string? defaultConfig = DefaultExtensions; var indexOfSelfPipeline = inputText.IndexOf(SelfPipelineHintTagStart, StringComparison.OrdinalIgnoreCase); if (indexOfSelfPipeline >= 0) { @@ -90,7 +92,7 @@ namespace Markdig.Extensions.SelfPipeline } } - if (!string.IsNullOrEmpty(defaultConfig)) + if (defaultConfig is { Length: > 0 }) { builder.Configure(defaultConfig); } diff --git a/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs b/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs index 172c7a84..96d1740a 100644 --- a/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs +++ b/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs @@ -1,6 +1,9 @@ // Copyright (c) Alexandre Mutel. All rights reserved. // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. + +#nullable enable + using System; using Markdig.Renderers; using Markdig.Renderers.Html; @@ -22,14 +25,14 @@ namespace Markdig.Extensions.SmartyPants /// /// The options. /// - public HtmlSmartyPantRenderer(SmartyPantOptions options) + public HtmlSmartyPantRenderer(SmartyPantOptions? options) { this.options = options ?? throw new ArgumentNullException(nameof(options)); } protected override void Write(HtmlRenderer renderer, SmartyPant obj) { - if (!options.Mapping.TryGetValue(obj.Type, out string text)) + if (!options.Mapping.TryGetValue(obj.Type, out string? text)) { DefaultOptions.Mapping.TryGetValue(obj.Type, out text); } diff --git a/src/Markdig/Extensions/SmartyPants/SmartyPantOptions.cs b/src/Markdig/Extensions/SmartyPants/SmartyPantOptions.cs index e51a40c2..1469b5d0 100644 --- a/src/Markdig/Extensions/SmartyPants/SmartyPantOptions.cs +++ b/src/Markdig/Extensions/SmartyPants/SmartyPantOptions.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System.Collections.Generic; namespace Markdig.Extensions.SmartyPants diff --git a/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs b/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs index c9ba64fc..90743ff8 100644 --- a/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs +++ b/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Parsers.Inlines; using Markdig.Renderers; @@ -16,7 +18,7 @@ namespace Markdig.Extensions.SmartyPants /// Initializes a new instance of the class. /// /// The options. - public SmartyPantsExtension(SmartyPantOptions options) + public SmartyPantsExtension(SmartyPantOptions? options) { Options = options ?? new SmartyPantOptions(); } diff --git a/src/Markdig/Extensions/Tables/PipeTableParser.cs b/src/Markdig/Extensions/Tables/PipeTableParser.cs index 3f649f4f..f368c10b 100644 --- a/src/Markdig/Extensions/Tables/PipeTableParser.cs +++ b/src/Markdig/Extensions/Tables/PipeTableParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -28,7 +30,7 @@ namespace Markdig.Extensions.Tables /// /// The linebreak parser to use /// The options. - public PipeTableParser(LineBreakInlineParser lineBreakParser, PipeTableOptions options = null) + public PipeTableParser(LineBreakInlineParser lineBreakParser, PipeTableOptions? options = null) { this.lineBreakParser = lineBreakParser ?? throw new ArgumentNullException(nameof(lineBreakParser)); OpeningCharacters = new[] { '|', '\n', '\r' }; @@ -59,7 +61,7 @@ namespace Markdig.Extensions.Tables var position = processor.GetSourcePosition(slice.Start, out int globalLineIndex, out int column); var localLineIndex = globalLineIndex - processor.LineIndex; - if (tableState == null) + if (tableState is null) { // A table could be preceded by an empty line or a line containing an inline @@ -92,8 +94,8 @@ namespace Markdig.Extensions.Tables tableState.LineIndex++; if (!isFirstLineEmpty) { - tableState.ColumnAndLineDelimiters.Add(processor.Inline); - tableState.EndOfLines.Add(processor.Inline); + tableState.ColumnAndLineDelimiters.Add(processor.Inline!); + tableState.EndOfLines.Add(processor.Inline!); } } else @@ -117,11 +119,10 @@ namespace Markdig.Extensions.Tables tableState.ColumnAndLineDelimiters.Add(processor.Inline); } - return true; } - public bool PostProcess(InlineProcessor state, Inline root, Inline lastChild, int postInlineProcessorIndex, bool isFinalProcessing) + public bool PostProcess(InlineProcessor state, Inline root, Inline? lastChild, int postInlineProcessorIndex, bool isFinalProcessing) { var container = root as ContainerInline; var tableState = state.ParserStates[Index] as TableState; @@ -135,17 +136,14 @@ namespace Markdig.Extensions.Tables } var child = container.LastChild; - List delimitersToRemove = null; + List? delimitersToRemove = null; while (child != null) { - var pipeDelimiter = child as PipeTableDelimiterInline; - if (pipeDelimiter != null) + if (child is PipeTableDelimiterInline pipeDelimiter) { - if (delimitersToRemove == null) - { - delimitersToRemove = new List(); - } + delimitersToRemove ??= new List(); + delimitersToRemove.Add(pipeDelimiter); } @@ -258,9 +256,9 @@ namespace Markdig.Extensions.Tables { while (true) { - if (lastElement is ContainerInline) + if (lastElement is ContainerInline lastElementContainer) { - var nextElement = ((ContainerInline) lastElement).LastChild; + var nextElement = lastElementContainer.LastChild; if (nextElement != null) { lastElement = nextElement; @@ -287,8 +285,8 @@ namespace Markdig.Extensions.Tables // Cell loop // Reconstruct the table from the delimiters - TableRow row = null; - TableRow firstRow = null; + TableRow? row = null; + TableRow? firstRow = null; for (int i = 0; i < delimiters.Count; i++) { var delimiter = delimiters[i]; @@ -298,10 +296,8 @@ namespace Markdig.Extensions.Tables if (row == null) { row = new TableRow(); - if (firstRow == null) - { - firstRow = row; - } + + firstRow ??= row; // If the first delimiter is a pipe and doesn't have any parent or previous sibling, for cases like: // 0) | a | b | \n @@ -318,8 +314,8 @@ namespace Markdig.Extensions.Tables // x // 1) | a | b \n // 2) a | b \n - Inline endOfCell = null; - Inline beginOfCell = null; + Inline? endOfCell = null; + Inline? beginOfCell = null; var cellContentIt = delimiter; while (true) { @@ -331,7 +327,7 @@ namespace Markdig.Extensions.Tables } // The cell begins at the first effective child after a | or the top ContainerInline (which is not necessary to bring into the tree + it contains an invalid span calculation) - if (cellContentIt is PipeTableDelimiterInline || (cellContentIt.GetType() == typeof(ContainerInline) && cellContentIt.Parent == null )) + if (cellContentIt is PipeTableDelimiterInline || (cellContentIt.GetType() == typeof(ContainerInline) && cellContentIt.Parent is null )) { beginOfCell = ((ContainerInline)cellContentIt).FirstChild; if (endOfCell == null) @@ -348,14 +344,13 @@ namespace Markdig.Extensions.Tables } } - // If the current deilimiter is a pipe `|` OR // the beginOfCell/endOfCell are not null and // either they are : // - different // - they contain a single element, but it is not a line break (\n) or an empty/whitespace Literal. // Then we can add a cell to the current row - if (!isLine || (beginOfCell != null && endOfCell != null && ( beginOfCell != endOfCell || !(beginOfCell is LineBreakInline || (beginOfCell is LiteralInline && ((LiteralInline)beginOfCell).Content.IsEmptyOrWhitespace()))))) + if (!isLine || (beginOfCell != null && endOfCell != null && ( beginOfCell != endOfCell || !(beginOfCell is LineBreakInline || (beginOfCell is LiteralInline beingOfCellLiteral && beingOfCellLiteral.Content.IsEmptyOrWhitespace()))))) { if (!isLine) { @@ -420,7 +415,7 @@ namespace Markdig.Extensions.Tables Debug.Assert(row != null); if (table.Span.IsEmpty) { - table.Span = row.Span; + table.Span = row!.Span; table.Line = row.Line; table.Column = row.Column; } @@ -470,7 +465,7 @@ namespace Markdig.Extensions.Tables return false; } - private static bool ParseHeaderString(Inline inline, out TableColumnAlign? align) + private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? align) { align = 0; var literal = inline as LiteralInline; @@ -493,10 +488,10 @@ namespace Markdig.Extensions.Tables return false; } - private List FindHeaderRow(List delimiters) + private List? FindHeaderRow(List delimiters) { bool isValidRow = false; - List aligns = null; + List? aligns = null; for (int i = 0; i < delimiters.Count; i++) { if (!IsLine(delimiters[i])) @@ -524,10 +519,9 @@ namespace Markdig.Extensions.Tables } // Create aligns until we may have a header row - if (aligns == null) - { - aligns = new List(); - } + + aligns ??= new List(); + aligns.Add(new TableColumnDefinition() { Alignment = align }); // If this is the last delimiter, we need to check the right side of the `|` delimiter @@ -572,20 +566,20 @@ namespace Markdig.Extensions.Tables return inline is LineBreakInline; } - private static bool IsStartOfLineColumnDelimiter(Inline inline) + private static bool IsStartOfLineColumnDelimiter(Inline? inline) { - if (inline == null) + if (inline is null) { return false; } var previous = inline.PreviousSibling; - if (previous == null) + if (previous is null) { return true; } - var literal = previous as LiteralInline; - if (literal != null) + + if (previous is LiteralInline literal) { if (!literal.Content.IsEmptyOrWhitespace()) { @@ -596,43 +590,42 @@ namespace Markdig.Extensions.Tables return previous == null || IsLine(previous); } - private static void TrimStart(Inline inline) + private static void TrimStart(Inline? inline) { while (inline is ContainerInline && !(inline is DelimiterInline)) { inline = ((ContainerInline)inline).FirstChild; } - var literal = inline as LiteralInline; - if (literal != null) + + if (inline is LiteralInline literal) { literal.Content.TrimStart(); } } - private static void TrimEnd(Inline inline) + private static void TrimEnd(Inline? inline) { - var literal = inline as LiteralInline; - if (literal != null) + if (inline is LiteralInline literal) { literal.Content.TrimEnd(); } } - private static bool IsNullOrSpace(Inline inline) + private static bool IsNullOrSpace(Inline? inline) { - if (inline == null) + if (inline is null) { return true; } - var literal = inline as LiteralInline; - if (literal != null) + + if (inline is LiteralInline literal) { return literal.Content.IsEmptyOrWhitespace(); } return false; } - private class TableState + private sealed class TableState { public TableState() { diff --git a/src/Markdig/Extensions/Yaml/YamlFrontMatterParser.cs b/src/Markdig/Extensions/Yaml/YamlFrontMatterParser.cs index 532d2e41..e98a6fd2 100644 --- a/src/Markdig/Extensions/Yaml/YamlFrontMatterParser.cs +++ b/src/Markdig/Extensions/Yaml/YamlFrontMatterParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Parsers; using Markdig.Syntax; diff --git a/src/Markdig/Helpers/CharHelper.cs b/src/Markdig/Helpers/CharHelper.cs index c2329393..087bbc60 100644 --- a/src/Markdig/Helpers/CharHelper.cs +++ b/src/Markdig/Helpers/CharHelper.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Globalization; using System.Collections.Generic; diff --git a/src/Markdig/Helpers/LinkHelper.cs b/src/Markdig/Helpers/LinkHelper.cs index 98deb9d9..db5e7f61 100644 --- a/src/Markdig/Helpers/LinkHelper.cs +++ b/src/Markdig/Helpers/LinkHelper.cs @@ -419,7 +419,7 @@ namespace Markdig.Helpers public static bool TryParseInlineLinkTrivia( ref StringSlice text, - out string? link, + [NotNullWhen(true)] out string? link, out SourceSpan unescapedLink, out string? title, out SourceSpan unescapedTitle, diff --git a/src/Markdig/Helpers/OrderedList.cs b/src/Markdig/Helpers/OrderedList.cs index 21a96232..f4e7d8d1 100644 --- a/src/Markdig/Helpers/OrderedList.cs +++ b/src/Markdig/Helpers/OrderedList.cs @@ -2,7 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Markdig.Helpers { @@ -12,7 +15,7 @@ namespace Markdig.Helpers /// Type of the list item /// /// We use a typed list and don't use extension methods because it would pollute all list implements and the top level namespace. - public class OrderedList : List + public class OrderedList : List where T: notnull { public OrderedList() { @@ -36,7 +39,7 @@ namespace Markdig.Helpers return false; } - public TItem Find() where TItem : T + public TItem? Find() where TItem : T { for (int i = 0; i < Count; i++) { @@ -48,13 +51,13 @@ namespace Markdig.Helpers return default; } - public bool TryFind(out TItem item) where TItem : T + public bool TryFind([NotNullWhen(true)] out TItem? item) where TItem : T { item = Find(); return item != null; } - public TItem FindExact() where TItem : T + public TItem? FindExact() where TItem : T { for (int i = 0; i < Count; i++) { diff --git a/src/Markdig/Markdown.cs b/src/Markdig/Markdown.cs index 3c04abbe..846a1ac4 100644 --- a/src/Markdig/Markdown.cs +++ b/src/Markdig/Markdown.cs @@ -95,9 +95,9 @@ namespace Markdig /// The pipeline used for the conversion. /// The result of the conversion /// if markdown document variable is null - public static string ToHtml(this MarkdownDocument document, MarkdownPipeline pipeline = null) + public static string ToHtml(this MarkdownDocument document, MarkdownPipeline? pipeline = null) { - if (document == null) ThrowHelper.ArgumentNullException(nameof(document)); + if (document is null) ThrowHelper.ArgumentNullException(nameof(document)); pipeline ??= new MarkdownPipelineBuilder().Build(); var renderer = pipeline.GetCacheableHtmlRenderer(); @@ -105,7 +105,7 @@ namespace Markdig renderer.Render(document); renderer.Writer.Flush(); - string html = renderer.Writer.ToString(); + string html = renderer.Writer.ToString()!; pipeline.ReleaseCacheableHtmlRenderer(renderer); return html; } diff --git a/src/Markdig/MarkdownExtensions.cs b/src/Markdig/MarkdownExtensions.cs index 4e1a80e9..f11481d0 100644 --- a/src/Markdig/MarkdownExtensions.cs +++ b/src/Markdig/MarkdownExtensions.cs @@ -538,9 +538,9 @@ namespace Markdig /// The pipeline (e.g: advanced for , pipetables+gridtables for and /// The extensions to activate as a string /// The modified pipeline - public static MarkdownPipelineBuilder Configure(this MarkdownPipelineBuilder pipeline, string extensions) + public static MarkdownPipelineBuilder Configure(this MarkdownPipelineBuilder pipeline, string? extensions) { - if (extensions == null) + if (extensions is null) { return pipeline; } diff --git a/src/Markdig/Parsers/BlockParser.cs b/src/Markdig/Parsers/BlockParser.cs index f232d763..4ac0b8a5 100644 --- a/src/Markdig/Parsers/BlockParser.cs +++ b/src/Markdig/Parsers/BlockParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Syntax; namespace Markdig.Parsers @@ -38,9 +40,9 @@ namespace Markdig.Parsers } // TODO: Add comment - public event ProcessBlockDelegate Closed; + public event ProcessBlockDelegate? Closed; - internal ProcessBlockDelegate GetClosedEvent => Closed; + internal ProcessBlockDelegate? GetClosedEvent => Closed; /// /// Determines whether this instance can interrupt the specified block being processed. diff --git a/src/Markdig/Parsers/BlockProcessor.cs b/src/Markdig/Parsers/BlockProcessor.cs index fcefc143..f6eae722 100644 --- a/src/Markdig/Parsers/BlockProcessor.cs +++ b/src/Markdig/Parsers/BlockProcessor.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -16,7 +18,7 @@ namespace Markdig.Parsers /// public class BlockProcessor { - private BlockProcessor root; + private readonly BlockProcessor? root; private int currentStackIndex; private readonly BlockParserStateCache parserStateCache; private int originalLineStart = 0; @@ -44,7 +46,7 @@ namespace Markdig.Parsers /// Whether to parse trivia such as whitespace, extra heading characters and unescaped string values. /// /// - public BlockProcessor(MarkdownDocument document, BlockParserList parsers, MarkdownParserContext context, bool trackTrivia = false) + public BlockProcessor(MarkdownDocument document, BlockParserList parsers, MarkdownParserContext? context, bool trackTrivia = false) { if (document == null) ThrowHelper.ArgumentNullException(nameof(document)); if (parsers == null) ThrowHelper.ArgumentNullException(nameof(parsers)); @@ -75,27 +77,27 @@ namespace Markdig.Parsers /// /// Gets the parser context or null if none is available. /// - public MarkdownParserContext Context { get; } + public MarkdownParserContext? Context { get; } /// /// Gets the current active container. /// - public ContainerBlock CurrentContainer { get; private set; } + public ContainerBlock? CurrentContainer { get; private set; } /// /// Gets the last block that is opened. /// - public Block CurrentBlock { get; private set; } + public Block? CurrentBlock { get; private set; } /// /// Gets the last block that is created. /// - public Block LastBlock { get; private set; } + public Block? LastBlock { get; private set; } /// /// Gets the next block in a . /// - public Block NextContinue => currentStackIndex + 1 < OpenedBlocks.Count ? OpenedBlocks[currentStackIndex + 1] : null; + public Block? NextContinue => currentStackIndex + 1 < OpenedBlocks.Count ? OpenedBlocks[currentStackIndex + 1] : null; /// /// Gets the root document. @@ -197,7 +199,7 @@ namespace Markdig.Parsers { var linesBefore = LinesBefore; LinesBefore = null; - return linesBefore; + return linesBefore!; } /// @@ -206,7 +208,7 @@ namespace Markdig.Parsers /// is relevant. Otherwise, the /// entry will contain trivia. /// - public List LinesBefore { get; set; } + public List? LinesBefore { get; set; } /// /// True to parse trivia such as whitespace, extra heading characters and unescaped @@ -226,7 +228,7 @@ namespace Markdig.Parsers container = container.Parent; } - return container; + return container!; } /// @@ -835,7 +837,7 @@ namespace Markdig.Parsers // If a block parser cannot interrupt a paragraph, and the last block is a paragraph // we can skip this parser - var lastBlock = CurrentBlock; + var lastBlock = CurrentBlock!; if (!blockParser.CanInterrupt(this, lastBlock)) { continue; @@ -960,10 +962,10 @@ namespace Markdig.Parsers } // If previous block is a container, add the new block as a children of the previous block - if (block.Parent == null) + if (block.Parent is null) { UpdateLastBlockAndContainer(); - CurrentContainer.Add(block); + CurrentContainer!.Add(block); } block.IsOpen = result.IsContinue(); diff --git a/src/Markdig/Parsers/FencedBlockParserBase.cs b/src/Markdig/Parsers/FencedBlockParserBase.cs index 9a742205..120ae7f0 100644 --- a/src/Markdig/Parsers/FencedBlockParserBase.cs +++ b/src/Markdig/Parsers/FencedBlockParserBase.cs @@ -2,6 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + +using System; + using Markdig.Helpers; using Markdig.Renderers.Html; using Markdig.Syntax; @@ -24,12 +28,12 @@ namespace Markdig.Parsers /// /// Gets or sets the information parser. /// - public InfoParserDelegate InfoParser { get; set; } + public InfoParserDelegate? InfoParser { get; set; } /// /// A delegates that allows to process attached attributes /// - public TryParseAttributesDelegate TryParseAttributes { get; set; } + public TryParseAttributesDelegate? TryParseAttributes { get; set; } } /// @@ -38,7 +42,6 @@ namespace Markdig.Parsers /// public abstract class FencedBlockParserBase : FencedBlockParserBase where T : Block, IFencedBlock { - /// /// Initializes a new instance of the class. /// @@ -52,7 +55,7 @@ namespace Markdig.Parsers /// /// Gets or sets the language prefix (default is "language-") /// - public string InfoPrefix { get; set; } + public string? InfoPrefix { get; set; } public int MinimumMatchCount { get; set; } @@ -79,11 +82,11 @@ namespace Markdig.Parsers { var start = line.Start; var end = start - 1; - StringSlice afterFence = new StringSlice(line.Text, start, end); - StringSlice info = new StringSlice(line.Text, start, end); - StringSlice afterInfo = new StringSlice(line.Text, start, end); - StringSlice arg = new StringSlice(line.Text, start, end); - StringSlice afterArg = new StringSlice(line.Text, start, end); + var afterFence = new StringSlice(line.Text, start, end); + var info = new StringSlice(line.Text, start, end); + var afterInfo = new StringSlice(line.Text, start, end); + var arg = new StringSlice(line.Text, start, end); + var afterArg = new StringSlice(line.Text, start, end); ParseState state = ParseState.AfterFence; for (int i = line.Start; i <= line.End; i++) @@ -182,7 +185,7 @@ namespace Markdig.Parsers public static bool DefaultInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced, char openingCharacter) { string infoString; - string argString = null; + string? argString = null; // An info string cannot contain any backticks (unless it is a tilde block) int firstSpace = -1; @@ -216,7 +219,7 @@ namespace Markdig.Parsers if (firstSpace > 0) { - infoString = line.Text.Substring(line.Start, firstSpace - line.Start).Trim(); + infoString = line.Text.AsSpan(line.Start, firstSpace - line.Start).Trim().ToString(); // Skip any spaces after info string firstSpace++; @@ -329,7 +332,7 @@ namespace Markdig.Parsers { block.UpdateSpanEnd(startBeforeTrim - 1); - var fencedBlock = block as IFencedBlock; + var fencedBlock = (IFencedBlock)block; fencedBlock.ClosingFencedCharCount = closingCount; fencedBlock.NewLine = processor.Line.NewLine; fencedBlock.TriviaBeforeClosingFence = processor.UseTrivia(sourcePosition - 1); diff --git a/src/Markdig/Parsers/FencedCodeBlockParser.cs b/src/Markdig/Parsers/FencedCodeBlockParser.cs index d53364b9..e944550d 100644 --- a/src/Markdig/Parsers/FencedCodeBlockParser.cs +++ b/src/Markdig/Parsers/FencedCodeBlockParser.cs @@ -2,9 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; -using System.ComponentModel; namespace Markdig.Parsers { diff --git a/src/Markdig/Parsers/HeadingBlockParser.cs b/src/Markdig/Parsers/HeadingBlockParser.cs index d283868a..865097f7 100644 --- a/src/Markdig/Parsers/HeadingBlockParser.cs +++ b/src/Markdig/Parsers/HeadingBlockParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System.Diagnostics; using Markdig.Helpers; using Markdig.Syntax; @@ -31,7 +33,7 @@ namespace Markdig.Parsers /// /// A delegates that allows to process attached attributes after # /// - public TryParseAttributesDelegate TryParseAttributes { get; set; } + public TryParseAttributesDelegate? TryParseAttributes { get; set; } public override BlockState TryOpen(BlockProcessor processor) { diff --git a/src/Markdig/Parsers/HtmlBlockParser.cs b/src/Markdig/Parsers/HtmlBlockParser.cs index 1ac6822e..23ac544a 100644 --- a/src/Markdig/Parsers/HtmlBlockParser.cs +++ b/src/Markdig/Parsers/HtmlBlockParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using Markdig.Helpers; using Markdig.Syntax; @@ -176,7 +178,6 @@ namespace Markdig.Parsers private const string EndOfCDATA = "]]>"; private const string EndOfProcessingInstruction = "?>"; - private BlockState MatchEnd(BlockProcessor state, HtmlBlock htmlBlock) { state.GoToColumn(state.ColumnBeforeIndent); diff --git a/src/Markdig/Parsers/IAttributesParseable.cs b/src/Markdig/Parsers/IAttributesParseable.cs index 00458575..29ce7450 100644 --- a/src/Markdig/Parsers/IAttributesParseable.cs +++ b/src/Markdig/Parsers/IAttributesParseable.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; @@ -25,6 +27,6 @@ namespace Markdig.Parsers /// /// A delegates that allows to process attached attributes /// - TryParseAttributesDelegate TryParseAttributes { get; set; } + TryParseAttributesDelegate? TryParseAttributes { get; set; } } } \ No newline at end of file diff --git a/src/Markdig/Parsers/IPostInlineProcessor.cs b/src/Markdig/Parsers/IPostInlineProcessor.cs index 56adf85c..6f67ebfd 100644 --- a/src/Markdig/Parsers/IPostInlineProcessor.cs +++ b/src/Markdig/Parsers/IPostInlineProcessor.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Syntax.Inlines; namespace Markdig.Parsers @@ -21,6 +23,6 @@ namespace Markdig.Parsers /// /// true to continue to the next delimiter processor; /// false to stop the process (in case a processor is performing sub-sequent processor itself) - bool PostProcess(InlineProcessor state, Inline root, Inline lastChild, int postInlineProcessorIndex, bool isFinalProcessing); + bool PostProcess(InlineProcessor state, Inline root, Inline? lastChild, int postInlineProcessorIndex, bool isFinalProcessing); } } \ No newline at end of file diff --git a/src/Markdig/Parsers/IndentedCodeBlockParser.cs b/src/Markdig/Parsers/IndentedCodeBlockParser.cs index 38cd28d1..973258f7 100644 --- a/src/Markdig/Parsers/IndentedCodeBlockParser.cs +++ b/src/Markdig/Parsers/IndentedCodeBlockParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; using System.Collections.Generic; @@ -52,7 +54,7 @@ namespace Markdig.Parsers return result; } - public override BlockState TryContinue(BlockProcessor processor, Block block) + public override BlockState TryContinue(BlockProcessor processor, Block? block) { if (!processor.IsCodeIndent || processor.IsBlankLine) { diff --git a/src/Markdig/Parsers/InlineParser.cs b/src/Markdig/Parsers/InlineParser.cs index ace5dac7..e2246b2d 100644 --- a/src/Markdig/Parsers/InlineParser.cs +++ b/src/Markdig/Parsers/InlineParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; namespace Markdig.Parsers diff --git a/src/Markdig/Parsers/InlineProcessor.cs b/src/Markdig/Parsers/InlineProcessor.cs index 22ce0446..99e7d6d8 100644 --- a/src/Markdig/Parsers/InlineProcessor.cs +++ b/src/Markdig/Parsers/InlineProcessor.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.IO; @@ -38,10 +40,10 @@ namespace Markdig.Parsers /// Whether to parse trivia such as whitespace, extra heading characters and unescaped string values. /// /// - public InlineProcessor(MarkdownDocument document, InlineParserList parsers, bool preciseSourcelocation, MarkdownParserContext context, bool trackTrivia = false) + public InlineProcessor(MarkdownDocument document, InlineParserList parsers, bool preciseSourcelocation, MarkdownParserContext? context, bool trackTrivia = false) { - if (document == null) ThrowHelper.ArgumentNullException(nameof(document)); - if (parsers == null) ThrowHelper.ArgumentNullException(nameof(parsers)); + if (document is null) ThrowHelper.ArgumentNullException(nameof(document)); + if (parsers is null) ThrowHelper.ArgumentNullException(nameof(parsers)); Document = document; Parsers = parsers; Context = context; @@ -55,7 +57,7 @@ namespace Markdig.Parsers /// /// Gets the current block being processed. /// - public LeafBlock Block { get; private set; } + public LeafBlock? Block { get; private set; } /// /// Gets a value indicating whether to provide precise source location. @@ -65,17 +67,17 @@ namespace Markdig.Parsers /// /// Gets or sets the new block to replace the block being processed. /// - public Block BlockNew { get; set; } + public Block? BlockNew { get; set; } /// /// Gets or sets the current inline. Used by to return a new inline if match was successfull /// - public Inline Inline { get; set; } + public Inline? Inline { get; set; } /// /// Gets the root container of the current . /// - public ContainerInline Root { get; internal set; } + public ContainerInline? Root { get; internal set; } /// /// Gets the list of inline parsers. @@ -85,7 +87,7 @@ namespace Markdig.Parsers /// /// Gets the parser context or null if none is available. /// - public MarkdownParserContext Context { get; } + public MarkdownParserContext? Context { get; } /// /// Gets the root document. @@ -100,12 +102,12 @@ namespace Markdig.Parsers /// /// Gets the parser states that can be used by using their property. /// - public object[] ParserStates { get; } + public object?[] ParserStates { get; } /// /// Gets or sets the debug log writer. No log if null. /// - public TextWriter DebugLog { get; set; } + public TextWriter? DebugLog { get; set; } /// /// True to parse trivia such as whitespace, extra heading characters and unescaped @@ -118,7 +120,6 @@ namespace Markdig.Parsers /// public LiteralInlineParser LiteralInlineParser { get; } - public int GetSourcePosition(int sliceOffset) { return GetSourcePosition(sliceOffset, out int lineIndex, out int column); @@ -308,7 +309,7 @@ namespace Markdig.Parsers //} } - public void PostProcessInlines(int startingIndex, Inline root, Inline lastChild, bool isFinalProcessing) + public void PostProcessInlines(int startingIndex, Inline root, Inline? lastChild, bool isFinalProcessing) { for (int i = startingIndex; i < Parsers.PostInlineProcessors.Length; i++) { @@ -322,7 +323,7 @@ namespace Markdig.Parsers private ContainerInline FindLastContainer() { - var container = Block.Inline; + var container = Block!.Inline; for (int depth = 0; ; depth++) { if (container.LastChild is ContainerInline nextContainer && !nextContainer.IsClosed) diff --git a/src/Markdig/Parsers/Inlines/CodeInlineParser.cs b/src/Markdig/Parsers/Inlines/CodeInlineParser.cs index 4631c1e9..ac9b00b2 100644 --- a/src/Markdig/Parsers/Inlines/CodeInlineParser.cs +++ b/src/Markdig/Parsers/Inlines/CodeInlineParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; using Markdig.Syntax.Inlines; diff --git a/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs b/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs index 80a7ce23..dcf92711 100644 --- a/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs +++ b/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs @@ -9,7 +9,7 @@ namespace Markdig.Parsers.Inlines /// /// Descriptor for an emphasis. /// - public class EmphasisDescriptor + public sealed class EmphasisDescriptor { /// /// Initializes a new instance of the class. @@ -33,21 +33,21 @@ namespace Markdig.Parsers.Inlines /// /// The character of this emphasis. /// - public readonly char Character; + public char Character { get; } /// /// The minimum number of character this emphasis is expected to have (must be >=1) /// - public readonly int MinimumCount; + public int MinimumCount { get; } /// /// The maximum number of character this emphasis is expected to have (must be >=1 and >= minimumCount) /// - public readonly int MaximumCount; + public int MaximumCount { get; } /// /// This emphasis can be used within a word. /// - public readonly bool EnableWithinWord; + public bool EnableWithinWord { get; } } } \ No newline at end of file diff --git a/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs b/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs index 52c168f4..e833c777 100644 --- a/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs +++ b/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; @@ -19,7 +21,7 @@ namespace Markdig.Parsers.Inlines /// public class EmphasisInlineParser : InlineParser, IPostInlineProcessor { - private CharacterMap emphasisMap; + private CharacterMap? emphasisMap; private readonly DelimitersObjectCache inlinesCache = new DelimitersObjectCache(); [Obsolete("Use TryCreateEmphasisInlineDelegate instead", error: false)] @@ -64,7 +66,7 @@ namespace Markdig.Parsers.Inlines /// Gets or sets the create emphasis inline delegate (allowing to create a different emphasis inline class) /// [Obsolete("Use TryCreateEmphasisInlineList instead", error: false)] - public CreateEmphasisInlineDelegate CreateEmphasisInline { get; set; } + public CreateEmphasisInlineDelegate? CreateEmphasisInline { get; set; } public readonly List TryCreateEmphasisInlineList = new List(); public override void Initialize() @@ -89,14 +91,14 @@ namespace Markdig.Parsers.Inlines emphasisMap = new CharacterMap(tempMap); } - public bool PostProcess(InlineProcessor state, Inline root, Inline lastChild, int postInlineProcessorIndex, bool isFinalProcessing) + public bool PostProcess(InlineProcessor state, Inline root, Inline? lastChild, int postInlineProcessorIndex, bool isFinalProcessing) { if (!(root is ContainerInline container)) { return true; } - List delimiters = null; + List? delimiters = null; if (container is EmphasisDelimiterInline emphasisDelimiter) { delimiters = inlinesCache.Get(); @@ -139,7 +141,7 @@ namespace Markdig.Parsers.Inlines // The amount of delimiter characters in the delimiter run may exceed emphasisDesc.MaximumCount, as that is handeled in `ProcessEmphasis` var delimiterChar = slice.CurrentChar; - var emphasisDesc = emphasisMap[delimiterChar]; + var emphasisDesc = emphasisMap![delimiterChar]; char pc = (char)0; if (processor.Inline is HtmlEntityInline htmlEntityInline) @@ -173,7 +175,7 @@ namespace Markdig.Parsers.Inlines char c = slice.CurrentChar; // The following character is actually an entity, we need to decode it - if (HtmlEntityParser.TryParse(ref slice, out string htmlString, out int htmlLength)) + if (HtmlEntityParser.TryParse(ref slice, out string? htmlString, out int htmlLength)) { c = htmlString[0]; } @@ -218,7 +220,7 @@ namespace Markdig.Parsers.Inlines { var closeDelimiter = delimiters[i]; // Skip delimiters not supported by this instance - EmphasisDescriptor emphasisDesc = emphasisMap[closeDelimiter.DelimiterChar]; + EmphasisDescriptor emphasisDesc = emphasisMap![closeDelimiter.DelimiterChar]; if (emphasisDesc == null) { continue; @@ -230,7 +232,7 @@ namespace Markdig.Parsers.Inlines { // Now, look back in the stack (staying above stack_bottom and the openers_bottom for this delimiter type) // for the first matching potential opener (“matching” means same delimiter). - EmphasisDelimiterInline openDelimiter = null; + EmphasisDelimiterInline? openDelimiter = null; int openDelimiterIndex = -1; for (int j = i - 1; j >= 0; j--) { @@ -260,7 +262,7 @@ namespace Markdig.Parsers.Inlines int delimiterDelta = Math.Min(Math.Min(openDelimiter.DelimiterCount, closeDelimiter.DelimiterCount), emphasisDesc.MaximumCount); // Insert an emph or strong emph node accordingly, after the text node corresponding to the opener. - EmphasisInline emphasis = null; + EmphasisInline? emphasis = null; { if (delimiterDelta <= 2) // We can try using the legacy delegate { @@ -293,7 +295,7 @@ namespace Markdig.Parsers.Inlines var openDelimitercount = openDelimiter.DelimiterCount; var closeDelimitercount = closeDelimiter.DelimiterCount; - emphasis.Span.Start = openDelimiter.Span.Start; + emphasis!.Span.Start = openDelimiter.Span.Start; emphasis.Line = openDelimiter.Line; emphasis.Column = openDelimiter.Column; emphasis.Span.End = closeDelimiter.Span.End - closeDelimitercount + delimiterDelta; diff --git a/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs b/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs index 11dd5685..030bb0a6 100644 --- a/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs +++ b/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs @@ -2,7 +2,11 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; +using System.Diagnostics.CodeAnalysis; + using Markdig.Helpers; using Markdig.Syntax; using Markdig.Syntax.Inlines; @@ -24,7 +28,7 @@ namespace Markdig.Parsers.Inlines } - public static bool TryParse(ref StringSlice slice, out string literal, out int match) + public static bool TryParse(ref StringSlice slice, [NotNullWhen(true)] out string? literal, out int match) { literal = null; match = HtmlHelper.ScanEntity(slice, out int entityValue, out int entityNameStart, out int entityNameLength); @@ -46,7 +50,7 @@ namespace Markdig.Parsers.Inlines public override bool Match(InlineProcessor processor, ref StringSlice slice) { - if (!TryParse(ref slice, out string literal, out int match)) + if (!TryParse(ref slice, out string? literal, out int match)) { return false; } diff --git a/src/Markdig/Parsers/Inlines/LineBreakInlineParser.cs b/src/Markdig/Parsers/Inlines/LineBreakInlineParser.cs index 123d65b9..f34178f4 100644 --- a/src/Markdig/Parsers/Inlines/LineBreakInlineParser.cs +++ b/src/Markdig/Parsers/Inlines/LineBreakInlineParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; using Markdig.Syntax.Inlines; diff --git a/src/Markdig/Parsers/Inlines/LinkInlineParser.cs b/src/Markdig/Parsers/Inlines/LinkInlineParser.cs index 0b482abd..9b5438fa 100644 --- a/src/Markdig/Parsers/Inlines/LinkInlineParser.cs +++ b/src/Markdig/Parsers/Inlines/LinkInlineParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; using Markdig.Syntax.Inlines; @@ -41,7 +43,7 @@ namespace Markdig.Parsers.Inlines return false; } } - string label; + string? label; SourceSpan labelWithTriviaSpan = SourceSpan.Empty; switch (c) { @@ -114,7 +116,7 @@ namespace Markdig.Parsers.Inlines private bool ProcessLinkReference( InlineProcessor state, StringSlice text, - string label, + string? label, SourceSpan labelWithriviaSpan, bool isShortcut, SourceSpan labelSpan, @@ -127,7 +129,7 @@ namespace Markdig.Parsers.Inlines return false; } - Inline link = null; + Inline? link = null; // Try to use a callback directly defined on the LinkReferenceDefinition if (linkRef.CreateLinkInline != null) { @@ -200,7 +202,7 @@ namespace Markdig.Parsers.Inlines private bool TryProcessLinkOrImage(InlineProcessor inlineState, ref StringSlice text) { - LinkDelimiterInline openParent = inlineState.Inline.FirstParentOfType(); + LinkDelimiterInline? openParent = inlineState.Inline!.FirstParentOfType(); if (openParent is null) { @@ -237,9 +239,9 @@ namespace Markdig.Parsers.Inlines { if (LinkHelper.TryParseInlineLinkTrivia( ref text, - out string url, + out string? url, out SourceSpan unescapedUrlSpan, - out string title, + out string? title, out SourceSpan unescapedTitleSpan, out char titleEnclosingCharacter, out SourceSpan linkSpan, @@ -297,7 +299,7 @@ namespace Markdig.Parsers.Inlines } else { - if (LinkHelper.TryParseInlineLink(ref text, out string url, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan)) + if (LinkHelper.TryParseInlineLink(ref text, out string? url, out string? title, out SourceSpan linkSpan, out SourceSpan titleSpan)) { // Inline Link var link = new LinkInline() @@ -338,7 +340,7 @@ namespace Markdig.Parsers.Inlines } var labelSpan = SourceSpan.Empty; - string label = null; + string? label = null; SourceSpan labelWithTrivia = SourceSpan.Empty; bool isLabelSpanLocal = true; @@ -401,7 +403,7 @@ namespace Markdig.Parsers.Inlines return false; } - private void MarkParentAsInactive(Inline inline) + private void MarkParentAsInactive(Inline? inline) { while (inline != null) { diff --git a/src/Markdig/Parsers/ListBlockParser.cs b/src/Markdig/Parsers/ListBlockParser.cs index 94f36542..49dc8bb4 100644 --- a/src/Markdig/Parsers/ListBlockParser.cs +++ b/src/Markdig/Parsers/ListBlockParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System.Collections.Generic; using Markdig.Helpers; using Markdig.Syntax; @@ -14,7 +16,7 @@ namespace Markdig.Parsers /// public class ListBlockParser : BlockParser { - private CharacterMap mapItemParsers; + private CharacterMap? mapItemParsers; /// /// Initializes a new instance of the class. @@ -179,10 +181,10 @@ namespace Markdig.Parsers return BlockState.None; } - private BlockState TryParseListItem(BlockProcessor state, Block block) + private BlockState TryParseListItem(BlockProcessor state, Block? block) { var currentListItem = block as ListItemBlock; - var currentParent = block as ListBlock ?? (ListBlock)currentListItem?.Parent; + var currentParent = block as ListBlock ?? (ListBlock)currentListItem?.Parent!; // We can early exit if we have a code indent and we are either (1) not in a ListItem, (2) preceded by a blank line, (3) in an unordered list if (state.IsCodeIndent && (currentListItem is null || currentListItem.LastChild is BlankLineBlock || !currentParent.IsOrdered)) @@ -196,7 +198,7 @@ namespace Markdig.Parsers var sourceEndPosition = state.Line.End; var c = state.CurrentChar; - var itemParser = mapItemParsers[c]; + var itemParser = mapItemParsers![c]; if (itemParser == null) { return BlockState.None; diff --git a/src/Markdig/Parsers/MarkdownParser.cs b/src/Markdig/Parsers/MarkdownParser.cs index af7d6851..e2735973 100644 --- a/src/Markdig/Parsers/MarkdownParser.cs +++ b/src/Markdig/Parsers/MarkdownParser.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using Markdig.Helpers; @@ -39,10 +41,10 @@ namespace Markdig.Parsers /// A parser context used for the parsing. /// /// - private MarkdownParser(string text, MarkdownPipeline pipeline, MarkdownParserContext context) + private MarkdownParser(string text, MarkdownPipeline pipeline, MarkdownParserContext? context) { - if (text == null) ThrowHelper.ArgumentNullException_text(); - if (pipeline == null) ThrowHelper.ArgumentNullException(nameof(pipeline)); + if (text is null) ThrowHelper.ArgumentNullException_text(); + if (pipeline is null) ThrowHelper.ArgumentNullException(nameof(pipeline)); trackTrivia = pipeline.TrackTrivia; roughLineCountEstimate = text.Length / 40; @@ -73,7 +75,7 @@ namespace Markdig.Parsers /// A parser context used for the parsing. /// An AST Markdown document /// if reader variable is null - public static MarkdownDocument Parse(string text, MarkdownPipeline pipeline = null, MarkdownParserContext context = null) + public static MarkdownDocument Parse(string text, MarkdownPipeline? pipeline = null, MarkdownParserContext? context = null) { if (text == null) ThrowHelper.ArgumentNullException_text(); pipeline ??= new MarkdownPipelineBuilder().Build(); @@ -118,8 +120,8 @@ namespace Markdig.Parsers { if (trackTrivia) { - Block lastBlock = blockProcessor.LastBlock; - if (lastBlock == null && document.Count == 0) + Block? lastBlock = blockProcessor.LastBlock; + if (lastBlock is null && document.Count == 0) { // this means we have unassigned characters var noBlocksFoundBlock = new EmptyBlock (null); @@ -177,7 +179,7 @@ namespace Markdig.Parsers { process_new_block: var item = blocks.Peek(); - var container = item.Container; + var container = item.Container!; for (; item.Index < container.Count; item.Index++) { @@ -222,14 +224,14 @@ namespace Markdig.Parsers } } item = blocks.Pop(); - container = item.Container; + container = item.Container!; container.OnProcessInlinesEnd(inlineProcessor); cache.Release(item); } } - private class ContainerItem + private sealed class ContainerItem { public ContainerItem() { @@ -240,9 +242,9 @@ namespace Markdig.Parsers Container = container; } - public ContainerBlock Container; + public ContainerBlock? Container { get; set; } - public int Index; + public int Index { get; set; } } } } \ No newline at end of file diff --git a/src/Markdig/Parsers/NumberedListItemParser.cs b/src/Markdig/Parsers/NumberedListItemParser.cs index 9803e64c..4315ee3c 100644 --- a/src/Markdig/Parsers/NumberedListItemParser.cs +++ b/src/Markdig/Parsers/NumberedListItemParser.cs @@ -2,8 +2,9 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; -using System.Text; namespace Markdig.Parsers { diff --git a/src/Markdig/Parsers/ParagraphBlockParser.cs b/src/Markdig/Parsers/ParagraphBlockParser.cs index e0a24ff4..df5c692b 100644 --- a/src/Markdig/Parsers/ParagraphBlockParser.cs +++ b/src/Markdig/Parsers/ParagraphBlockParser.cs @@ -2,9 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; -using System.Diagnostics; namespace Markdig.Parsers { diff --git a/src/Markdig/Parsers/ParserBase.cs b/src/Markdig/Parsers/ParserBase.cs index f7226502..427fc1bc 100644 --- a/src/Markdig/Parsers/ParserBase.cs +++ b/src/Markdig/Parsers/ParserBase.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + namespace Markdig.Parsers { /// @@ -14,7 +16,7 @@ namespace Markdig.Parsers /// /// Gets the opening characters this parser will be triggered if the character is found. /// - public char[] OpeningCharacters { get; set; } + public char[]? OpeningCharacters { get; set; } /// /// Initializes this parser with the specified parser processor. diff --git a/src/Markdig/Parsers/ParserList.cs b/src/Markdig/Parsers/ParserList.cs index 0998072f..3c005247 100644 --- a/src/Markdig/Parsers/ParserList.cs +++ b/src/Markdig/Parsers/ParserList.cs @@ -2,7 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. -using System; +#nullable enable + using System.Collections.Generic; using System.Runtime.CompilerServices; using Markdig.Helpers; @@ -15,10 +16,10 @@ namespace Markdig.Parsers /// Type of the parser /// The type of the parser state. /// - public abstract class ParserList : OrderedList where T : ParserBase + public abstract class ParserList : OrderedList where T : notnull, ParserBase { private readonly CharacterMap charMap; - private readonly T[] globalParsers; + private readonly T[]? globalParsers; protected ParserList(IEnumerable parsersArg) : base(parsersArg) { @@ -28,7 +29,7 @@ namespace Markdig.Parsers for (int i = 0; i < Count; i++) { var parser = this[i]; - if (parser == null) + if (parser is null) { ThrowHelper.InvalidOperationException("Unexpected null parser found"); } @@ -60,11 +61,11 @@ namespace Markdig.Parsers var tempCharMap = new Dictionary(); foreach (var parser in this) { - if (parser.OpeningCharacters != null && parser.OpeningCharacters.Length != 0) + if (parser.OpeningCharacters is { Length: > 0 }) { foreach (var openingChar in parser.OpeningCharacters) { - if (!tempCharMap.TryGetValue(openingChar, out T[] parsers)) + if (!tempCharMap.TryGetValue(openingChar, out T[]? parsers)) { parsers = new T[charCounter[openingChar]]; tempCharMap[openingChar] = parsers; @@ -77,7 +78,7 @@ namespace Markdig.Parsers } else { - globalParsers[globalParsers.Length - globalCounter] = parser; + globalParsers![globalParsers.Length - globalCounter] = parser; globalCounter--; } } @@ -88,7 +89,7 @@ namespace Markdig.Parsers /// /// Gets the list of global parsers (that don't have any opening characters defined) /// - public T[] GlobalParsers => globalParsers; + public T[]? GlobalParsers => globalParsers; /// /// Gets all the opening characters defined. diff --git a/src/Markdig/Parsers/QuoteBlockParser.cs b/src/Markdig/Parsers/QuoteBlockParser.cs index 641c566a..412d7b3c 100644 --- a/src/Markdig/Parsers/QuoteBlockParser.cs +++ b/src/Markdig/Parsers/QuoteBlockParser.cs @@ -2,9 +2,10 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; -using System.Diagnostics; namespace Markdig.Parsers { diff --git a/src/Markdig/Renderers/MarkdownObjectRenderer.cs b/src/Markdig/Renderers/MarkdownObjectRenderer.cs index 55579eda..63549bb7 100644 --- a/src/Markdig/Renderers/MarkdownObjectRenderer.cs +++ b/src/Markdig/Renderers/MarkdownObjectRenderer.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using Markdig.Syntax; diff --git a/src/Markdig/Syntax/Inlines/Inline.cs b/src/Markdig/Syntax/Inlines/Inline.cs index 2c5ec08c..c46b1646 100644 --- a/src/Markdig/Syntax/Inlines/Inline.cs +++ b/src/Markdig/Syntax/Inlines/Inline.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using System; using System.Collections.Generic; using System.IO; @@ -18,17 +20,17 @@ namespace Markdig.Syntax.Inlines /// /// Gets the parent container of this inline. /// - public ContainerInline Parent { get; internal set; } + public ContainerInline? Parent { get; internal set; } /// /// Gets the previous inline. /// - public Inline PreviousSibling { get; private set; } + public Inline? PreviousSibling { get; private set; } /// /// Gets the next sibling inline. /// - public Inline NextSibling { get; internal set; } + public Inline? NextSibling { get; internal set; } /// /// Gets or sets a value indicating whether this instance is closed. @@ -224,7 +226,7 @@ namespace Markdig.Syntax.Inlines } } - public T FirstParentOfType() where T : Inline + public T? FirstParentOfType() where T : notnull, Inline { var inline = this; while (inline != null) @@ -250,7 +252,7 @@ namespace Markdig.Syntax.Inlines continue; } - current = current.PreviousSibling; + current = current.PreviousSibling!; } return current; diff --git a/src/Markdig/Syntax/MarkdownObject.cs b/src/Markdig/Syntax/MarkdownObject.cs index 08fc9c24..7d645cee 100644 --- a/src/Markdig/Syntax/MarkdownObject.cs +++ b/src/Markdig/Syntax/MarkdownObject.cs @@ -2,6 +2,8 @@ // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. +#nullable enable + using Markdig.Helpers; using System; @@ -113,7 +115,7 @@ namespace Markdig.Syntax /// The key. /// The associated data or null if none /// if key is null - public object GetData(object key) + public object? GetData(object key) { if (key == null) ThrowHelper.ArgumentNullException_key(); if (attachedDatas == null) @@ -138,7 +140,7 @@ namespace Markdig.Syntax /// public bool RemoveData(object key) { - if (key == null) ThrowHelper.ArgumentNullException_key(); + if (key is null) ThrowHelper.ArgumentNullException_key(); if (attachedDatas == null) { return true;