diff --git a/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs b/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs index a26cde6966..5160baa5db 100644 --- a/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs +++ b/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs @@ -1,5 +1,6 @@ namespace BizHawk.Analyzers; +using System; using System.Collections.Immutable; using Microsoft.CodeAnalysis; @@ -10,6 +11,12 @@ using Microsoft.CodeAnalysis.Diagnostics; [DiagnosticAnalyzer(LanguageNames.CSharp)] public class HawkSourceAnalyzer : DiagnosticAnalyzer { + private const string ERR_MSG_LIST_EXPR_EMPTY = "Empty collection expression should be `[ ]`"; + + private const string ERR_MSG_LIST_EXPR_END = "Collection expression should end with ` ]`"; + + private const string ERR_MSG_LIST_EXPR_START = "Collection expression should start with `[ `"; + private const string ERR_MSG_SWITCH_THROWS_UNKNOWN = "Indeterminable exception type in default switch branch, should be InvalidOperationException/SwitchExpressionException"; private const string ERR_MSG_SWITCH_THROWS_WRONG_TYPE = "Incorrect exception type in default switch branch, should be InvalidOperationException/SwitchExpressionException"; @@ -22,6 +29,14 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + private static readonly DiagnosticDescriptor DiagListExprSpacing = new( + id: "BHI1110", + title: "Brackets of collection expression should be separated with spaces", + messageFormat: "{0}", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + private static readonly DiagnosticDescriptor DiagNoAnonClasses = new( id: "BHI1002", title: "Do not use anonymous types (classes)", @@ -64,6 +79,7 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create( DiagInterpStringIsDollarAt, + DiagListExprSpacing, DiagNoAnonClasses, DiagNoAnonDelegates, DiagNoDiscardingLocals, @@ -72,6 +88,24 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer public override void Initialize(AnalysisContext context) { + static string? CheckSpacingInList( + SeparatedSyntaxList listContents, + SyntaxToken openBracketToken, + Func serialiseOuter) + where T : SyntaxNode + { + if (listContents.Count is 0) return serialiseOuter() is "[ ]" ? null : ERR_MSG_LIST_EXPR_EMPTY; + var contentsWithTrivia = listContents.ToFullString(); + if (contentsWithTrivia.Contains("\n")) return null; // don't need to police spaces for multi-line expressions + if (contentsWithTrivia.Length > 1 + ? (contentsWithTrivia[contentsWithTrivia.Length - 1] is not ' ' + || contentsWithTrivia[contentsWithTrivia.Length - 2] is ' ' or '\t') + : contentsWithTrivia[0] is not ' ') + { + return ERR_MSG_LIST_EXPR_END; + } + return openBracketToken.TrailingTrivia.ToFullString() is " " ? null : ERR_MSG_LIST_EXPR_START; + } static bool IsDiscard(AssignmentExpressionSyntax aes) => aes.OperatorToken.RawKind is (int) SyntaxKind.EqualsToken && aes.Left is IdentifierNameSyntax { Identifier.Text: "_" }; context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); @@ -97,9 +131,17 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer case AssignmentExpressionSyntax aes when IsDiscard(aes) && snac.SemanticModel.GetSymbolInfo(aes.Right).Symbol?.Kind is SymbolKind.Local: snac.ReportDiagnostic(Diagnostic.Create(DiagNoDiscardingLocals, snac.Node.GetLocation())); break; + case CollectionExpressionSyntax ces: + var cesError = CheckSpacingInList(ces.Elements, ces.OpenBracketToken, ces.ToFullString); + if (cesError is not null) snac.ReportDiagnostic(Diagnostic.Create(DiagListExprSpacing, ces.GetLocation(), cesError)); + break; case InterpolatedStringExpressionSyntax ises: if (ises.StringStartToken.Text[0] is '@') snac.ReportDiagnostic(Diagnostic.Create(DiagInterpStringIsDollarAt, ises.GetLocation())); break; + case ListPatternSyntax lps: + var lpsError = CheckSpacingInList(lps.Patterns, lps.OpenBracketToken, lps.ToFullString); + if (lpsError is not null) snac.ReportDiagnostic(Diagnostic.Create(DiagListExprSpacing, lps.GetLocation(), lpsError)); + break; case QueryExpressionSyntax: snac.ReportDiagnostic(Diagnostic.Create(DiagNoQueryExpression, snac.Node.GetLocation())); break; @@ -125,7 +167,9 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer }, SyntaxKind.AnonymousObjectCreationExpression, SyntaxKind.AnonymousMethodExpression, + SyntaxKind.CollectionExpression, SyntaxKind.InterpolatedStringExpression, + SyntaxKind.ListPattern, SyntaxKind.QueryExpression, SyntaxKind.SimpleAssignmentExpression, SyntaxKind.SwitchExpressionArm); diff --git a/References/BizHawk.Analyzer.dll b/References/BizHawk.Analyzer.dll index 286a276777..eee77cb385 100644 Binary files a/References/BizHawk.Analyzer.dll and b/References/BizHawk.Analyzer.dll differ diff --git a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs index a43ad6e575..4abed96323 100644 --- a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs +++ b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs @@ -259,7 +259,7 @@ namespace BizHawk.Client.Common break; case 2 when _shaderChainScanlines is { Available: true }: selectedChain = _shaderChainScanlines; - selectedChainProperties = [new("uIntensity", 1.0f - GlobalConfig.TargetScanlineFilterIntensity / 256.0f)]; + selectedChainProperties = [ new("uIntensity", 1.0f - GlobalConfig.TargetScanlineFilterIntensity / 256.0f) ]; break; case 3 when _shaderChainUser is { Available: true }: selectedChain = _shaderChainUser; diff --git a/src/BizHawk.Tests/Common/checksums/SHA1Tests.cs b/src/BizHawk.Tests/Common/checksums/SHA1Tests.cs index 753e841567..55dcd8143b 100644 --- a/src/BizHawk.Tests/Common/checksums/SHA1Tests.cs +++ b/src/BizHawk.Tests/Common/checksums/SHA1Tests.cs @@ -13,8 +13,8 @@ namespace BizHawk.Tests.Common.checksums [TestMethod] public void TestSHA1Empty() { - byte[] data = []; // empty data - byte[] expectedSha = [0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09]; + byte[] data = [ ]; // empty data + byte[] expectedSha = [ 0xDA, 0x39, 0xA3, 0xEE, 0x5E, 0x6B, 0x4B, 0x0D, 0x32, 0x55, 0xBF, 0xEF, 0x95, 0x60, 0x18, 0x90, 0xAF, 0xD8, 0x07, 0x09 ]; Assert.IsTrue(expectedSha.SequenceEqual(SHA1Checksum.Compute(data))); } @@ -23,7 +23,7 @@ namespace BizHawk.Tests.Common.checksums public void TestSHA1Simple() { byte[] data = "hash"u8.ToArray(); // random short data - byte[] expectedSha = [0x23, 0x46, 0xad, 0x27, 0xd7, 0x56, 0x8b, 0xa9, 0x89, 0x6f, 0x1b, 0x7d, 0xa6, 0xb5, 0x99, 0x12, 0x51, 0xde, 0xbd, 0xf2]; + byte[] expectedSha = [ 0x23, 0x46, 0xAD, 0x27, 0xD7, 0x56, 0x8B, 0xA9, 0x89, 0x6F, 0x1B, 0x7D, 0xA6, 0xB5, 0x99, 0x12, 0x51, 0xDE, 0xBD, 0xF2 ]; Assert.IsTrue(expectedSha.SequenceEqual(SHA1Checksum.Compute(data))); Assert.IsTrue(expectedSha.SequenceEqual(SHA1Checksum.ComputeConcat(Array.Empty(), data))); @@ -40,17 +40,17 @@ namespace BizHawk.Tests.Common.checksums { const string testString = "The quick brown fox jumps over the lazy dog."; byte[] data = Encoding.ASCII.GetBytes(testString); - byte[] expectedSha1 = [0x40, 0x8d, 0x94, 0x38, 0x42, 0x16, 0xf8, 0x90, 0xff, 0x7a, 0x0c, 0x35, 0x28, 0xe8, 0xbe, 0xd1, 0xe0, 0xb0, 0x16, 0x21]; + byte[] expectedSha1 = [ 0x40, 0x8D, 0x94, 0x38, 0x42, 0x16, 0xF8, 0x90, 0xFF, 0x7A, 0x0C, 0x35, 0x28, 0xE8, 0xBE, 0xD1, 0xE0, 0xB0, 0x16, 0x21 ]; Assert.IsTrue(expectedSha1.SequenceEqual(SHA1Checksum.Compute(data))); data = new byte[65]; Encoding.ASCII.GetBytes(testString).CopyTo(data, 0); - byte[] expectedSha2 = [0x65, 0x87, 0x84, 0xE2, 0x68, 0xBF, 0xB1, 0x67, 0x94, 0x7B, 0xB7, 0xF3, 0xFB, 0x76, 0x69, 0x62, 0x79, 0x3E, 0x8C, 0x46]; + byte[] expectedSha2 = [ 0x65, 0x87, 0x84, 0xE2, 0x68, 0xBF, 0xB1, 0x67, 0x94, 0x7B, 0xB7, 0xF3, 0xFB, 0x76, 0x69, 0x62, 0x79, 0x3E, 0x8C, 0x46 ]; Assert.IsTrue(expectedSha2.SequenceEqual(SHA1Checksum.Compute(new Span(data, 0, 64)))); - byte[] expectedSha3 = [0x34, 0xF3, 0xA2, 0x57, 0xBD, 0x12, 0x5E, 0x6E, 0x0E, 0x28, 0xD0, 0xE5, 0xDA, 0xBE, 0x22, 0x28, 0x97, 0xFA, 0x69, 0x55]; + byte[] expectedSha3 = [ 0x34, 0xF3, 0xA2, 0x57, 0xBD, 0x12, 0x5E, 0x6E, 0x0E, 0x28, 0xD0, 0xE5, 0xDA, 0xBE, 0x22, 0x28, 0x97, 0xFA, 0x69, 0x55 ]; Assert.IsTrue(expectedSha3.SequenceEqual(SHA1Checksum.Compute(data))); } }