Add Analyzer to enforce spaces in `[]`

This commit is contained in:
YoshiRulz 2024-05-30 10:22:01 +10:00
parent e7c093eac6
commit b5ff65f2cb
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
4 changed files with 51 additions and 7 deletions

View File

@ -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<DiagnosticDescriptor> 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<T>(
SeparatedSyntaxList<T> listContents,
SyntaxToken openBracketToken,
Func<string> 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);

Binary file not shown.

View File

@ -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;

View File

@ -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<byte>(), 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<byte>(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)));
}
}