From 0743a1f8ea59f48c09bbee1a7e244aff9054f49d Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Wed, 30 Jul 2025 02:36:35 +1000 Subject: [PATCH] Add Analyzer for banning `init;` props turns out you can write to `readonly` fields from these, which is a convention I'm not willing to break --- .global.editorconfig.ini | 2 + .../BizHawk.Analyzer/HawkSourceAnalyzer.cs | 13 +++ .../HawkSourceAnalyzerTests.cs | 11 ++ References/BizHawk.Analyzer.dll | Bin 68608 -> 69120 bytes .../FilesystemFilterSet.cs | 4 +- .../RetroAchievements.Memory.cs | 24 ++-- .../config/SNES/BSNESOptions.cs | 106 ++++++++++++++---- .../Nintendo/BSNES/BsnesControllers.cs | 8 +- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 22 ++-- .../Nintendo/SNES/SNESGraphicsDecoder.cs | 66 +++++------ .../Consoles/Nintendo/SameBoy/SameBoy.cs | 23 ++-- 11 files changed, 180 insertions(+), 99 deletions(-) diff --git a/.global.editorconfig.ini b/.global.editorconfig.ini index a06ffaaee8..34c537797e 100644 --- a/.global.editorconfig.ini +++ b/.global.editorconfig.ini @@ -19,6 +19,8 @@ dotnet_diagnostic.BHI1005.severity = silent dotnet_diagnostic.BHI1006.severity = error # Don't use target-typed new for throw expressions dotnet_diagnostic.BHI1007.severity = error +# Do not use init setter +dotnet_diagnostic.BHI1008.severity = error # Don't call this.GetType() in sealed type, use typeof operator dotnet_diagnostic.BHI1100.severity = error # Don't call this.GetType(), use typeof operator (or replace subtype check with better encapsulation) diff --git a/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs b/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs index 7b53834a93..99603d5325 100644 --- a/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs +++ b/ExternalProjects/BizHawk.Analyzer/HawkSourceAnalyzer.cs @@ -55,6 +55,14 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + private static readonly DiagnosticDescriptor DiagNoInitAccessor = new( + id: "BHI1008", + title: "Do not use init setter", + messageFormat: "Use a regular `set`ter (or add a constructor parameter)", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: false); + private static readonly DiagnosticDescriptor DiagNoQueryExpression = new( id: "BHI1003", title: "Do not use query expression syntax", @@ -119,6 +127,7 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer DiagNoAnonClasses, DiagNoAnonDelegates, DiagNoDiscardingLocals, + DiagNoInitAccessor, DiagNoQueryExpression, DiagRecordImplicitlyRefType, DiagSwitchShouldThrowIOE, @@ -170,6 +179,9 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer } switch (snac.Node) { + case AccessorDeclarationSyntax ads: + if (ads.Keyword.ToString() is "init") DiagNoInitAccessor.ReportAt(ads, snac); + break; case AnonymousMethodExpressionSyntax: DiagNoAnonDelegates.ReportAt(snac.Node, snac); break; @@ -218,6 +230,7 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer SyntaxKind.AnonymousObjectCreationExpression, SyntaxKind.AnonymousMethodExpression, SyntaxKind.CollectionExpression, + SyntaxKind.InitAccessorDeclaration, SyntaxKind.InterpolatedStringExpression, SyntaxKind.ListPattern, SyntaxKind.QueryExpression, diff --git a/ExternalProjects/BizHawk.AnalyzersTests/BizHawk.Analyzer/HawkSourceAnalyzerTests.cs b/ExternalProjects/BizHawk.AnalyzersTests/BizHawk.Analyzer/HawkSourceAnalyzerTests.cs index 6fe7b9424e..1c2b94424e 100644 --- a/ExternalProjects/BizHawk.AnalyzersTests/BizHawk.Analyzer/HawkSourceAnalyzerTests.cs +++ b/ExternalProjects/BizHawk.AnalyzersTests/BizHawk.Analyzer/HawkSourceAnalyzerTests.cs @@ -101,6 +101,17 @@ public sealed class HawkSourceAnalyzerTests } """); + [TestMethod] + public Task CheckMisuseOfInitAccessor() + => Verify.VerifyAnalyzerAsync(""" + public sealed class Cases { + public int A { get; {|BHI1008:init;|} } + } + namespace System.Runtime.CompilerServices { + public static class IsExternalInit {} // this sample is compiled for lowest-common-denominator of `netstandard2.0`, so `init` accessor gives an error without this + } + """); + [TestMethod] public Task CheckMisuseOfInterpolatedString() => Verify.VerifyAnalyzerAsync(""" diff --git a/References/BizHawk.Analyzer.dll b/References/BizHawk.Analyzer.dll index 87d944b9e699d2e1754d9127d6186eb05c6f4b89..d912a3b3063653087e9cd617163b2eed13177ebf 100644 GIT binary patch delta 21236 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 XB<-*TJHm0|dTDJL_3??=T4ek`U2?H7 delta 21038 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 CombinedExts => Filters.SelectMany(static filter => filter.Extensions).Distinct().Order().ToList(); diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.Memory.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.Memory.cs index 443235d49f..c519a1afc3 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.Memory.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.Memory.cs @@ -107,9 +107,11 @@ namespace BizHawk.Client.EmuHawk private readonly uint _domainAddrStart; // addr of _domain where bank begins private readonly uint _addressMangler; // of course, let's *not* correct internal core byteswapping! - public ReadMemoryFunc ReadFunc { get; protected init; } - public WriteMemoryFunc WriteFunc { get; protected init; } - public ReadMemoryBlockFunc ReadBlockFunc { get; protected init; } + public virtual ReadMemoryFunc ReadFunc { get; } + + public virtual WriteMemoryFunc WriteFunc { get; } + + public virtual ReadMemoryBlockFunc ReadBlockFunc { get; } public uint StartAddress; // this is set for our rcheevos impl public readonly uint BankSize; @@ -192,13 +194,17 @@ namespace BizHawk.Client.EmuHawk private class NullMemFunctions : MemFunctions { + public override ReadMemoryFunc ReadFunc + => null; + + public override WriteMemoryFunc WriteFunc + => null; + + public override ReadMemoryBlockFunc ReadBlockFunc + => null; + public NullMemFunctions(long bankSize) - : base(null, 0, bankSize) - { - ReadFunc = null; - WriteFunc = null; - ReadBlockFunc = null; - } + : base(null, 0, bankSize) {} } // this is a complete hack because the libretro Intelli core sucks and so achievements are made expecting this format diff --git a/src/BizHawk.Client.EmuHawk/config/SNES/BSNESOptions.cs b/src/BizHawk.Client.EmuHawk/config/SNES/BSNESOptions.cs index aa447d8e46..57ba126b56 100644 --- a/src/BizHawk.Client.EmuHawk/config/SNES/BSNESOptions.cs +++ b/src/BizHawk.Client.EmuHawk/config/SNES/BSNESOptions.cs @@ -97,31 +97,31 @@ namespace BizHawk.Client.EmuHawk private bool AlwaysDoubleSize { get => cbDoubleSize.Checked; - init => cbDoubleSize.Checked = value; + set => cbDoubleSize.Checked = value; } private bool CropSGBFrame { get => cbCropSGBFrame.Checked; - init => cbCropSGBFrame.Checked = value; + set => cbCropSGBFrame.Checked = value; } private bool NoPPUSpriteLimit { get => cbNoPPUSpriteLimit.Checked; - init => cbNoPPUSpriteLimit.Checked = value; + set => cbNoPPUSpriteLimit.Checked = value; } private bool ShowOverscan { get => cbShowOverscan.Checked; - init => cbShowOverscan.Checked = value; + set => cbShowOverscan.Checked = value; } private bool ShowCursor { get => cbShowCursor.Checked; - init => cbShowCursor.Checked = value; + set => cbShowCursor.Checked = value; } private BsnesApi.ASPECT_RATIO_CORRECTION AspectRatioCorrection => (BsnesApi.ASPECT_RATIO_CORRECTION)AspectRatioCorrectionBox.SelectedIndex; @@ -129,43 +129,43 @@ namespace BizHawk.Client.EmuHawk private bool Hotfixes { get => cbGameHotfixes.Checked; - init => cbGameHotfixes.Checked = value; + set => cbGameHotfixes.Checked = value; } private bool FastPPU { get => cbFastPPU.Checked; - init => cbDoubleSize.Enabled = cbNoPPUSpriteLimit.Enabled = cbFastPPU.Checked = value; + set => cbDoubleSize.Enabled = cbNoPPUSpriteLimit.Enabled = cbFastPPU.Checked = value; } private bool FastDSP { get => cbFastDSP.Checked; - init => cbFastDSP.Checked = value; + set => cbFastDSP.Checked = value; } private bool FastCoprocessors { get => cbFastCoprocessor.Checked; - init => cbFastCoprocessor.Checked = value; + set => cbFastCoprocessor.Checked = value; } private bool UseSGB2 { get => cbUseSGB2.Checked; - init => cbUseSGB2.Checked = value; + set => cbUseSGB2.Checked = value; } private bool UseRealTime { get => cbUseRealTime.Checked; - init => cbUseRealTime.Checked = value; + set => cbUseRealTime.Checked = value; } private DateTime InitialTime { get => dtpInitialTime.Value; - init => dtpInitialTime.Value = value; + set => dtpInitialTime.Value = value; } private BsnesApi.ENTROPY Entropy => (BsnesApi.ENTROPY) EntropyBox.SelectedIndex; @@ -174,19 +174,77 @@ namespace BizHawk.Client.EmuHawk private BsnesCore.SATELLAVIEW_CARTRIDGE SatellaviewCartridge => (BsnesCore.SATELLAVIEW_CARTRIDGE)SatellaviewCartridgeBox.SelectedIndex; - private bool ShowObj1 { get => Obj1Checkbox.Checked; init => Obj1Checkbox.Checked = value; } - private bool ShowObj2 { get => Obj2Checkbox.Checked; init => Obj2Checkbox.Checked = value; } - private bool ShowObj3 { get => Obj3Checkbox.Checked; init => Obj3Checkbox.Checked = value; } - private bool ShowObj4 { get => Obj4Checkbox.Checked; init => Obj4Checkbox.Checked = value; } + private bool ShowObj1 + { + get => Obj1Checkbox.Checked; + set => Obj1Checkbox.Checked = value; + } - private bool ShowBg1_0 { get => Bg1_0Checkbox.Checked; init => Bg1_0Checkbox.Checked = value; } - private bool ShowBg1_1 { get => Bg1_1Checkbox.Checked; init => Bg1_1Checkbox.Checked = value; } - private bool ShowBg2_0 { get => Bg2_0Checkbox.Checked; init => Bg2_0Checkbox.Checked = value; } - private bool ShowBg2_1 { get => Bg2_1Checkbox.Checked; init => Bg2_1Checkbox.Checked = value; } - private bool ShowBg3_0 { get => Bg3_0Checkbox.Checked; init => Bg3_0Checkbox.Checked = value; } - private bool ShowBg3_1 { get => Bg3_1Checkbox.Checked; init => Bg3_1Checkbox.Checked = value; } - private bool ShowBg4_0 { get => Bg4_0Checkbox.Checked; init => Bg4_0Checkbox.Checked = value; } - private bool ShowBg4_1 { get => Bg4_1Checkbox.Checked; init => Bg4_1Checkbox.Checked = value; } + private bool ShowObj2 + { + get => Obj2Checkbox.Checked; + set => Obj2Checkbox.Checked = value; + } + + private bool ShowObj3 + { + get => Obj3Checkbox.Checked; + set => Obj3Checkbox.Checked = value; + } + + private bool ShowObj4 + { + get => Obj4Checkbox.Checked; + set => Obj4Checkbox.Checked = value; + } + + private bool ShowBg1_0 + { + get => Bg1_0Checkbox.Checked; + set => Bg1_0Checkbox.Checked = value; + } + + private bool ShowBg1_1 + { + get => Bg1_1Checkbox.Checked; + set => Bg1_1Checkbox.Checked = value; + } + + private bool ShowBg2_0 + { + get => Bg2_0Checkbox.Checked; + set => Bg2_0Checkbox.Checked = value; + } + + private bool ShowBg2_1 + { + get => Bg2_1Checkbox.Checked; + set => Bg2_1Checkbox.Checked = value; + } + + private bool ShowBg3_0 + { + get => Bg3_0Checkbox.Checked; + set => Bg3_0Checkbox.Checked = value; + } + + private bool ShowBg3_1 + { + get => Bg3_1Checkbox.Checked; + set => Bg3_1Checkbox.Checked = value; + } + + private bool ShowBg4_0 + { + get => Bg4_0Checkbox.Checked; + set => Bg4_0Checkbox.Checked = value; + } + + private bool ShowBg4_1 + { + get => Bg4_1Checkbox.Checked; + set => Bg4_1Checkbox.Checked = value; + } private void BtnOk_Click(object sender, EventArgs e) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs index 6d0b6d2f05..6c6712ee77 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs @@ -17,10 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES BSNES_INPUT_DEVICE.None => new BsnesUnpluggedController(), BSNES_INPUT_DEVICE.Gamepad => new BsnesController(), BSNES_INPUT_DEVICE.ExtendedGamepad => new BsnesExtendedController(), - BSNES_INPUT_DEVICE.Mouse => new BsnesMouseController - { - LimitAnalogChangeSensitivity = ss.LimitAnalogChangeSensitivity - }, + BSNES_INPUT_DEVICE.Mouse => new BsnesMouseController(LimitAnalogChangeSensitivity: ss.LimitAnalogChangeSensitivity), BSNES_INPUT_DEVICE.SuperMultitap => new BsnesMultitapController(), BSNES_INPUT_DEVICE.Payload => new BsnesPayloadController(), BSNES_INPUT_DEVICE.SuperScope => new BsnesSuperScopeController(), @@ -171,14 +168,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES } } - internal class BsnesMouseController : IBsnesController + internal class BsnesMouseController(bool LimitAnalogChangeSensitivity = true) : IBsnesController { private static readonly ControllerDefinition _definition = new ControllerDefinition("(SNES Controller fragment)") { BoolButtons = { "0Mouse Left", "0Mouse Right" } } .AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); public ControllerDefinition Definition => _definition; - public bool LimitAnalogChangeSensitivity { get; init; } = true; public short GetState(IController controller, int index, int id) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index cea40cdc22..170202ad6a 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -642,24 +642,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { throw new InvalidOperationException("Unexpected error in gambatte_getmemoryarea"); } - return new GPUMemoryAreas - { - Vram = _vram, - Oam = _oam, - Sppal = _sppal, - Bgpal = _bgpal, - }; + return new GPUMemoryAreas(vram: _vram, oam: _oam, sppal: _sppal, bgpal: _bgpal); } - private class GPUMemoryAreas : IGPUMemoryAreas + private sealed class GPUMemoryAreas(IntPtr vram, IntPtr oam, IntPtr sppal, IntPtr bgpal) : IGPUMemoryAreas { - public IntPtr Vram { get; init; } + public IntPtr Vram + => vram; - public IntPtr Oam { get; init; } + public IntPtr Oam + => oam; - public IntPtr Sppal { get; init; } + public IntPtr Sppal + => sppal; - public IntPtr Bgpal { get; init; } + public IntPtr Bgpal + => bgpal; public void Dispose() {} } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs index f5376281c1..9b14e674c9 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs @@ -350,45 +350,45 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public BGInfos BG = new BGInfos(); - public int Mode { get; init; } - public bool Mode1_BG3_Priority { get; init; } + public int Mode { get; internal set; } + public bool Mode1_BG3_Priority { get; internal set; } - public bool SETINI_Mode7ExtBG { get; init; } - public bool SETINI_HiRes { get; init; } - public bool SETINI_Overscan { get; init; } - public bool SETINI_ObjInterlace { get; init; } - public bool SETINI_ScreenInterlace { get; init; } + public bool SETINI_Mode7ExtBG { get; internal set; } + public bool SETINI_HiRes { get; internal set; } + public bool SETINI_Overscan { get; internal set; } + public bool SETINI_ObjInterlace { get; internal set; } + public bool SETINI_ScreenInterlace { get; internal set; } - public int CGWSEL_ColorMask { get; init; } - public int CGWSEL_ColorSubMask { get; init; } - public int CGWSEL_AddSubMode { get; init; } - public bool CGWSEL_DirectColor { get; init; } - public int CGADSUB_AddSub { get; init; } - public bool CGADSUB_Half { get; init; } + public int CGWSEL_ColorMask { get; internal set; } + public int CGWSEL_ColorSubMask { get; internal set; } + public int CGWSEL_AddSubMode { get; internal set; } + public bool CGWSEL_DirectColor { get; internal set; } + public int CGADSUB_AddSub { get; internal set; } + public bool CGADSUB_Half { get; internal set; } - public int OBSEL_Size { get; init; } - public int OBSEL_NameSel { get; init; } - public int OBSEL_NameBase { get; init; } + public int OBSEL_Size { get; internal set; } + public int OBSEL_NameSel { get; internal set; } + public int OBSEL_NameBase { get; internal set; } - public int OBJTable0Addr { get; init; } - public int OBJTable1Addr { get; init; } + public int OBJTable0Addr { get; internal set; } + public int OBJTable1Addr { get; internal set; } - public bool OBJ_MainEnabled { get; init; } - public bool OBJ_SubEnabled { get; init; } - public bool OBJ_MathEnabled { get; init; } - public bool BK_MathEnabled { get; init; } + public bool OBJ_MainEnabled { get; internal set; } + public bool OBJ_SubEnabled { get; internal set; } + public bool OBJ_MathEnabled { get; internal set; } + public bool BK_MathEnabled { get; internal set; } - public int M7HOFS { get; init; } - public int M7VOFS { get; init; } - public int M7A { get; init; } - public int M7B { get; init; } - public int M7C { get; init; } - public int M7D { get; init; } - public int M7X { get; init; } - public int M7Y { get; init; } - public int M7SEL_REPEAT { get; init; } - public bool M7SEL_HFLIP { get; init; } - public bool M7SEL_VFLIP { get; init; } + public int M7HOFS { get; internal set; } + public int M7VOFS { get; internal set; } + public int M7A { get; internal set; } + public int M7B { get; internal set; } + public int M7C { get; internal set; } + public int M7D { get; internal set; } + public int M7X { get; internal set; } + public int M7Y { get; internal set; } + public int M7SEL_REPEAT { get; internal set; } + public bool M7SEL_HFLIP { get; internal set; } + public bool M7SEL_VFLIP { get; internal set; } } public static readonly int[,] ModeBpps = { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs index 7422996869..37de9285ba 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs @@ -270,25 +270,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy { throw new InvalidOperationException("Unexpected error in sameboy_getmemoryarea"); } - - return new GPUMemoryAreas() - { - Vram = _vram, - Oam = _oam, - Sppal = _sppal, - Bgpal = _bgpal - }; + return new GPUMemoryAreas(vram: _vram, oam: _oam, sppal: _sppal, bgpal: _bgpal); } - private class GPUMemoryAreas : IGPUMemoryAreas + private sealed class GPUMemoryAreas(IntPtr vram, IntPtr oam, IntPtr sppal, IntPtr bgpal) : IGPUMemoryAreas { - public IntPtr Vram { get; init; } + public IntPtr Vram + => vram; - public IntPtr Oam { get; init; } + public IntPtr Oam + => oam; - public IntPtr Sppal { get; init; } + public IntPtr Sppal + => sppal; - public IntPtr Bgpal { get; init; } + public IntPtr Bgpal + => bgpal; public void Dispose() {} }