diff --git a/.editorconfig b/.editorconfig index 6236ee8..ffccaa5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,65 +10,40 @@ trim_trailing_whitespace = true [*.{yml,props,targets,csproj}] indent_size = 2 +[*.cs] # IDE0079: Remove unnecessary suppression dotnet_remove_unnecessary_suppression_exclusions = category:ReSharper -# IDE0079: Remove unnecessary suppression -# dotnet_diagnostic.IDE0079.severity = none - -# CA2255: The 'ModuleInitializer' attribute should not be used in libraries -dotnet_diagnostic.CA2255.severity = none - -# CS8600: Converting null literal or possible null value to non-nullable type. -dotnet_diagnostic.CS8600.severity = error - -# CS8601: Possible null reference assignment. -dotnet_diagnostic.CS8601.severity = error - -# CS8602: Dereference of a possibly null reference. -dotnet_diagnostic.CS8602.severity = error - -# CS8603: Possible null reference return. -dotnet_diagnostic.CS8603.severity = error - -# CS8604: Possible null reference argument. -dotnet_diagnostic.CS8604.severity = error - -# CS8610: Nullability of reference types in type of parameter doesn't match overridden member. -dotnet_diagnostic.CS8610.severity = error - -# CS8613: Nullability of reference types in return type doesn't match implicitly implemented member. -dotnet_diagnostic.CS8613.severity = error - -# CS8614: Nullability of reference types in type of parameter doesn't match implicitly implemented member. -dotnet_diagnostic.CS8614.severity = error - -# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable. -dotnet_diagnostic.CS8618.severity = error - -# CS8619: Nullability of reference types in value doesn't match target type. -dotnet_diagnostic.CS8619.severity = error - -# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types. -dotnet_diagnostic.CS8620.severity = error - -# CS8625: Cannot convert null literal to non-nullable reference type. -dotnet_diagnostic.CS8625.severity = error - -# CS8634: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'class' constraint. -dotnet_diagnostic.CS8634.severity = error - -# CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type. -dotnet_diagnostic.CS8643.severity = error - -# CS8653: A default expression introduces a null value for a type parameter. -dotnet_diagnostic.CS8653.severity = error - -# CS8714: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. -dotnet_diagnostic.CS8714.severity = error - -# IDE0059: Unnecessary assigment of a value -dotnet_diagnostic.IDE0059.severity = none - -# IDE0060: Remove unused parameter -dotnet_diagnostic.IDE0060.severity = none +[tests/**.cs] +# CA1707: Identifiers should not contain underscores +# Tests follow the Method_Condition_ExpectedResult naming convention. +dotnet_diagnostic.CA1707.severity = none + +# CA1304, CA1305, CA1311: culture-sensitive calls +# Tests cover all StringComparison values and change the current culture on purpose. +dotnet_diagnostic.CA1304.severity = none +dotnet_diagnostic.CA1305.severity = none +dotnet_diagnostic.CA1311.severity = none + +# CA1861: Avoid constant arrays as arguments +# CA1866: Use char overload +# Test inputs are built per test case; the performance of test code is irrelevant. +dotnet_diagnostic.CA1861.severity = none +dotnet_diagnostic.CA1866.severity = none + +[benchmarks/**.cs] +# CA1707: Identifiers should not contain underscores +# Underscores keep the generated BenchmarkDotNet report readable. +dotnet_diagnostic.CA1707.severity = none + +# CA1822: Mark members as static +# BenchmarkDotNet discovers instance methods and properties. +dotnet_diagnostic.CA1822.severity = none + +# CA2201: Do not raise reserved exception types +# Benchmark setup throws Exception to abort a run on an unexpected parser result. +dotnet_diagnostic.CA2201.severity = none + +# CA1806: Do not ignore method results +# Benchmarks intentionally ignore TryParse results. +dotnet_diagnostic.CA1806.severity = none diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d0da5db..b6f6990 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: - name: Install .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 9.0.x + dotnet-version: 10.0.x - name: Checkout uses: actions/checkout@v4 diff --git a/Directory.Build.props b/Directory.Build.props index ed14ea7..9e6caca 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,4 +2,18 @@ true + + + $(NoWarn);CS0649 + true + + + + true + latest + Recommended + Default + true + true + diff --git a/benchmarks/Parsers/PidginParsers.cs b/benchmarks/Parsers/PidginParsers.cs index 7e3359e..7b73926 100644 --- a/benchmarks/Parsers/PidginParsers.cs +++ b/benchmarks/Parsers/PidginParsers.cs @@ -94,7 +94,7 @@ public static class JsonParser Char('r').Select (_ => '\r'), Char('t').Select (_ => '\t'), Char('u').Then(HexDigit.Repeat(4) - .Select(h => (char)int.Parse(new string(h.ToArray()), NumberStyles.HexNumber))) + .Select(h => (char)int.Parse(new string(h.ToArray()), NumberStyles.HexNumber, CultureInfo.InvariantCulture))) ) ) ).ManyString().Between(Quote) diff --git a/samples/TinyC/TinyCParser.cs b/samples/TinyC/TinyCParser.cs index f1731c6..8f53813 100644 --- a/samples/TinyC/TinyCParser.cs +++ b/samples/TinyC/TinyCParser.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Globalization; using Ramstack.Parsing; @@ -21,7 +22,7 @@ private static Parser CreateParser() var number = Set("0-9") .OneOrMore() - .Map(Node (m) => Node.Number(int.Parse(m))) + .Map(Node (m) => Node.Number(int.Parse(m, NumberStyles.Integer, CultureInfo.InvariantCulture))) .As("number"); var variable = diff --git a/src/Ramstack.Parsing/NumberKind.cs b/src/Ramstack.Parsing/NumberKind.cs index 8f83838..77ad650 100644 --- a/src/Ramstack.Parsing/NumberKind.cs +++ b/src/Ramstack.Parsing/NumberKind.cs @@ -3,6 +3,8 @@ namespace Ramstack.Parsing; /// /// Specifies the types of numeric string representations. /// +[SuppressMessage("Naming", "CA1720:Identifier contains type name", + Justification = "The members name the numeric kinds, not the corresponding .NET types.")] public enum NumberKind { /// diff --git a/src/Ramstack.Parsing/OptionalValue.cs b/src/Ramstack.Parsing/OptionalValue.cs index a7b69c0..f0145f9 100644 --- a/src/Ramstack.Parsing/OptionalValue.cs +++ b/src/Ramstack.Parsing/OptionalValue.cs @@ -4,6 +4,8 @@ namespace Ramstack.Parsing; /// Represents an optional value of type . /// /// The underlying type of the optional value. +[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", + Justification = "For performance reasons, the field is read in place, while a property getter would copy large T values on every access.")] public readonly struct OptionalValue { /// diff --git a/src/Ramstack.Parsing/Parser.Optional.cs b/src/Ramstack.Parsing/Parser.Optional.cs index 66b0409..6d8d316 100644 --- a/src/Ramstack.Parsing/Parser.Optional.cs +++ b/src/Ramstack.Parsing/Parser.Optional.cs @@ -37,15 +37,18 @@ private sealed class OptionalParser(Parser parser) : Parser public override bool TryParse(ref ParseContext context, out OptionalValue value) { - value = default; - if (parser.TryParse(ref context, out var result)) { + Unsafe.SkipInit(out value); + + // Write directly into the caller's slot: constructing OptionalValue here + // would copy T into a temporary and then into `value`. Unsafe.AsRef(in value.Value) = result; Unsafe.AsRef(in value.HasValue) = true; } else { + value = default; context.Advance(0); } diff --git a/src/Ramstack.Parsing/PositionBookmark.cs b/src/Ramstack.Parsing/PositionBookmark.cs index 7b3d55f..ac67542 100644 --- a/src/Ramstack.Parsing/PositionBookmark.cs +++ b/src/Ramstack.Parsing/PositionBookmark.cs @@ -9,7 +9,7 @@ public readonly struct PositionBookmark /// /// Gets the zero-based parsing position. /// - public readonly int Position; + public int Position { get; } /// /// Initializes a new instance of the structure. diff --git a/src/Ramstack.Parsing/Ramstack.Parsing.csproj b/src/Ramstack.Parsing/Ramstack.Parsing.csproj index 3be5e70..51957c6 100644 --- a/src/Ramstack.Parsing/Ramstack.Parsing.csproj +++ b/src/Ramstack.Parsing/Ramstack.Parsing.csproj @@ -10,11 +10,6 @@ true - - 649;1591 - CS8600;CS8601;CS8602;CS8603;CS8604;CS8610;CS8613;CS8614;CS8618;CS8619;CS8620;CS8625;CS8643;CS8653;CS8714 - - https://github.com/rameel/ramstack.parsing Rameel diff --git a/src/Ramstack.Parsing/Utilities/CharClassExtensions.cs b/src/Ramstack.Parsing/Utilities/CharClassExtensions.cs index 3b1b20d..3542781 100644 --- a/src/Ramstack.Parsing/Utilities/CharClassExtensions.cs +++ b/src/Ramstack.Parsing/Utilities/CharClassExtensions.cs @@ -335,7 +335,7 @@ _ when controls.Contains(c) => "\\" + c, else { sb.Append("\\u"); - sb.Append(((ushort)c).ToString("x4")); + sb.Append(((ushort)c).ToString("x4", provider: null)); } }