Add Analyzer to enforce exception type for default switch branches
This commit is contained in:
parent
90fe31529e
commit
4f98733c29
|
@ -12,6 +12,9 @@
|
|||
|
||||
<!-- Verbatim interpolated strings should begin $@, not @$ -->
|
||||
<Rule Id="BHI1004" Action="Error" />
|
||||
|
||||
<!-- Default branch of switch expression should throw InvalidOperationException/SwitchExpressionException or not throw -->
|
||||
<Rule Id="BHI1005" Action="Error" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="DocumentationAnalyzers" RuleNamespace="DocumentationAnalyzers.StyleRules">
|
||||
<!-- Place text in paragraphs -->
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
namespace BizHawk.Analyzers;
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
@ -10,6 +11,10 @@ using Microsoft.CodeAnalysis.Diagnostics;
|
|||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
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";
|
||||
|
||||
private static readonly DiagnosticDescriptor DiagInterpStringIsDollarAt = new(
|
||||
id: "BHI1004",
|
||||
title: "Verbatim interpolated strings should begin $@, not @$",
|
||||
|
@ -42,11 +47,20 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
|||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true);
|
||||
|
||||
private static readonly DiagnosticDescriptor DiagSwitchShouldThrowIOE = new(
|
||||
id: "BHI1005",
|
||||
title: "Default branch of switch expression should throw InvalidOperationException/SwitchExpressionException or not throw",
|
||||
messageFormat: "{0}",
|
||||
category: "Usage",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(
|
||||
DiagInterpStringIsDollarAt,
|
||||
DiagNoAnonClasses,
|
||||
DiagNoAnonDelegates,
|
||||
DiagNoQueryExpression);
|
||||
DiagNoQueryExpression,
|
||||
DiagSwitchShouldThrowIOE);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
|
@ -69,11 +83,37 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
|||
case QueryExpressionSyntax:
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoQueryExpression, snac.Node.GetLocation()));
|
||||
break;
|
||||
case SwitchExpressionArmSyntax { WhenClause: null, Pattern: DiscardPatternSyntax, Expression: ThrowExpressionSyntax tes }:
|
||||
if (tes.Expression is ObjectCreationExpressionSyntax oces)
|
||||
{
|
||||
// to resolve edge-cases involving aliases, you're supposed to use `snac.SemanticModel.GetTypeInfo(oces.Type).ConvertedType?.Name`, but I couldn't get it to work
|
||||
if (((oces.Type as IdentifierNameSyntax)?.Identifier)?.ToString() is "SwitchExpressionException" or nameof(InvalidOperationException))
|
||||
{
|
||||
// correct usage, do not flag
|
||||
}
|
||||
else
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagSwitchShouldThrowIOE, tes.GetLocation(), ERR_MSG_SWITCH_THROWS_WRONG_TYPE));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// code reads `throw <something weird>`
|
||||
snac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagSwitchShouldThrowIOE,
|
||||
tes.GetLocation(),
|
||||
DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
ERR_MSG_SWITCH_THROWS_UNKNOWN));
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
SyntaxKind.AnonymousObjectCreationExpression,
|
||||
SyntaxKind.AnonymousMethodExpression,
|
||||
SyntaxKind.InterpolatedStringExpression,
|
||||
SyntaxKind.QueryExpression);
|
||||
SyntaxKind.QueryExpression,
|
||||
SyntaxKind.SwitchExpressionArm);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -257,7 +257,7 @@ namespace BizHawk.Bizware.DirectX
|
|||
BlendEquationMode.Max => BlendOperation.Maximum,
|
||||
BlendEquationMode.Min => BlendOperation.Minimum,
|
||||
BlendEquationMode.FuncReverseSubtract => BlendOperation.ReverseSubtract,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ namespace BizHawk.Bizware.DirectX
|
|||
BlendingFactorSrc.Src1Color => throw new NotSupportedException(),
|
||||
BlendingFactorSrc.OneMinusSrc1Color => throw new NotSupportedException(),
|
||||
BlendingFactorSrc.OneMinusSrc1Alpha => throw new NotSupportedException(),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
|
||||
public void SetBlendState(IBlendState rsBlend)
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace BizHawk.Client.Common
|
|||
VSystemID.Raw.SGB => CoreSystem.SuperGameBoy,
|
||||
VSystemID.Raw.UZE => CoreSystem.UzeBox,
|
||||
VSystemID.Raw.PCFX => CoreSystem.PcFx,
|
||||
_ => throw new IndexOutOfRangeException($"{value} is missing in convert list")
|
||||
_ => throw new InvalidOperationException($"{value} is missing in convert list")
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace BizHawk.Client.Common
|
|||
CoreSystem.ZXSpectrum => VSystemID.Raw.ZXSpectrum,
|
||||
CoreSystem.AmstradCPC => VSystemID.Raw.AmstradCPC,
|
||||
CoreSystem.Odyssey2 => VSystemID.Raw.O2,
|
||||
_ => throw new IndexOutOfRangeException($"{value} is missing in convert list")
|
||||
_ => throw new InvalidOperationException($"{value} is missing in convert list")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace BizHawk.Client.Common
|
|||
/// <remarks>should probably centralise these enum extensions and not-extensions somewhere... --yoshi</remarks>
|
||||
public static class DisplaySurfaceIDParser
|
||||
{
|
||||
#pragma warning disable BHI1005 // switching on string, possibly from user input, ArgumentException is correct here
|
||||
[return: NotNullIfNotNull("str")]
|
||||
public static DisplaySurfaceID? Parse(string? str) => str?.ToLowerInvariant() switch
|
||||
{
|
||||
|
@ -24,12 +25,13 @@ namespace BizHawk.Client.Common
|
|||
"native" => DisplaySurfaceID.Client,
|
||||
_ => throw new ArgumentException(message: $"{str} is not the name of a display surface", paramName: nameof(str))
|
||||
};
|
||||
#pragma warning restore BHI1005
|
||||
|
||||
public static string GetName(this DisplaySurfaceID surfaceID) => surfaceID switch
|
||||
{
|
||||
DisplaySurfaceID.EmuCore => "emucore",
|
||||
DisplaySurfaceID.Client => "client",
|
||||
_ => throw new ArgumentException(message: "not a valid enum member", paramName: nameof(surfaceID))
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1023,7 +1023,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
DisplaySurfaceID.EmuCore => (GameExtraPadding.Left + _currEmuWidth + GameExtraPadding.Right, GameExtraPadding.Top + _currEmuHeight + GameExtraPadding.Bottom),
|
||||
DisplaySurfaceID.Client => (currNativeWidth, currNativeHeight),
|
||||
_ => throw new ArgumentException(message: "not a valid enum member", paramName: nameof(surfaceID))
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
|
||||
IDisplaySurface ret = sdss.AllocateSurface(width, height, clear);
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
EMsgBoxIcon.Question => MessageBoxIcon.Question,
|
||||
EMsgBoxIcon.Warning => MessageBoxIcon.Warning,
|
||||
EMsgBoxIcon.Info => MessageBoxIcon.Information,
|
||||
_ => throw new ArgumentException(message: "not a valid enum member", paramName: nameof(icon))
|
||||
_ => throw new InvalidOperationException()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
EHostInputMethod.OpenTK => new OpenTKInputAdapter(),
|
||||
_ when OSTailoredCode.IsUnixHost => new OpenTKInputAdapter(),
|
||||
EHostInputMethod.DirectInput => new DirectInputAdapter(),
|
||||
_ => throw new Exception()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
Console.WriteLine($"Using {Adapter.Desc} for host input (keyboard + gamepads)");
|
||||
Adapter.UpdateConfig(_currentConfig);
|
||||
|
|
|
@ -774,7 +774,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
WatchSize.DWord => WatchSize.Word,
|
||||
WatchSize.Word => WatchSize.Byte,
|
||||
_ => throw new Exception()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
var a = Watch.GenerateWatch(ab.Domain, ab.Address, newSize, ab.Type, ab.BigEndian, ab.Notes);
|
||||
var b = Watch.GenerateWatch(ab.Domain, ab.Address + (int) newSize, newSize, ab.Type, ab.BigEndian, ab.Notes);
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace BizHawk.Common
|
|||
DistinctOS.Linux => new UnixMonoLLManager(),
|
||||
DistinctOS.macOS => new UnixMonoLLManager(),
|
||||
DistinctOS.Windows => new WindowsLLManager(),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new InvalidOperationException()
|
||||
});
|
||||
|
||||
public static ILinkedLibManager LinkedLibManager => _LinkedLibManager.Value;
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
{
|
||||
0x20 or 0xfc => 3,
|
||||
0x22 => 4,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
ColorType.vbabgbold => OldVBAColor,
|
||||
ColorType.gba => GBAColor,
|
||||
ColorType.libretrogbc => LibretroGBCColor,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(c)),
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
"ARM v5 (Thumb)" => LibMelonDS.TraceMask.ARM9_THUMB,
|
||||
"ARM v4" => LibMelonDS.TraceMask.ARM7_ARM,
|
||||
"ARM v4 (Thumb)" => LibMelonDS.TraceMask.ARM7_THUMB,
|
||||
_ => throw new Exception("Invalid CPU mode?"),
|
||||
_ => throw new InvalidOperationException("Invalid CPU mode?")
|
||||
};
|
||||
|
||||
if (Cpu.Length == 14)
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|||
ScreenSize.ABAB_64x32 => new Dimensions(2, 1),
|
||||
ScreenSize.AABB_32x64 => new Dimensions(1, 2),
|
||||
ScreenSize.ABCD_64x64 => new Dimensions(2, 2),
|
||||
_ => throw new Exception()
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace BizHawk.Emulation.Cores
|
|||
"guncon" => NymaGunCon(num),
|
||||
"justifier" => NymaKonamiJustifier(num),
|
||||
"dancepad" => NymaDancePad(num),
|
||||
_ => throw new NotSupportedException($"device {device} is not supported"),
|
||||
_ => throw new InvalidOperationException($"device {device} is not supported")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue