From f10fb87474d685e26952b2798c6516905e2ff853 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sun, 26 Mar 2023 16:59:58 +0100 Subject: [PATCH] Update LangVersion to C# 9. mono was the bottleneck restricting our ability to use a newer C# version. mono 6.12 is currently available. Although poorly documented on their website, this supports C# 9. https://www.mono-project.com/docs/about-mono/versioning/#mono-source-versioning indicates mono 6.12 uses Roslyn 3.9.0. https://github.com/dotnet/roslyn/blob/main/docs/wiki/NuGet-packages.md#versioning indicates Roslyn 3.9.0 supports C# 9. This unlocks C# 8 and C# 9 features previously unavailable to us. - https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-80 - https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-9 A newer version of StyleCop is required to avoid rules tripping up on the new syntax. Currently only prerelease versions are available but their use is encouraged https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3420#issuecomment-994899135 Fix style rule violations on existing rules where the newer language version makes some existing casts redundant or allows use of the null coalescing assignment operator. --- .editorconfig | 29 +++++++++++-------- Directory.Build.props | 5 ++-- INSTALL.md | 4 +-- Makefile | 6 ++-- OpenRA.Game/Exts.cs | 6 ++-- OpenRA.Mods.Common/Activities/Move/Move.cs | 2 +- .../Graphics/DefaultSpriteSequence.cs | 2 +- OpenRA.Mods.Common/Pathfinder/PathSearch.cs | 2 +- .../Scripting/Global/ReinforcementsGlobal.cs | 4 +-- .../RepairableBuildingProperties.cs | 4 +-- OpenRA.Mods.Common/Traits/Cargo.cs | 2 +- OpenRA.Mods.Common/Traits/Turreted.cs | 2 +- .../20221203/ExplicitSequenceFilenames.cs | 2 +- .../Logic/Ingame/MenuButtonsChromeLogic.cs | 2 +- .../Widgets/Logic/Lobby/LobbyLogic.cs | 2 +- packaging/macos/checkmono.c | 2 +- packaging/macos/launcher.m | 2 +- packaging/macos/utility.m | 2 +- 18 files changed, 42 insertions(+), 38 deletions(-) diff --git a/.editorconfig b/.editorconfig index 5c773a289e4f..93badf243a62 100644 --- a/.editorconfig +++ b/.editorconfig @@ -63,7 +63,7 @@ dotnet_diagnostic.IDE0044.severity = warning # IDE0062 Make local function static #csharp_prefer_static_local_function = true -dotnet_diagnostic.IDE0062.severity = silent # Requires C# 8 +dotnet_diagnostic.IDE0062.severity = silent # Requires C# 8 - TODO Consider enabling # IDE0064 Make struct fields writable # No options @@ -137,15 +137,15 @@ dotnet_diagnostic.IDE0050.severity = silent # IDE0054/IDE0074 Use compound assignment/Use coalesce compound assignment #dotnet_style_prefer_compound_assignment = true dotnet_diagnostic.IDE0054.severity = warning -dotnet_diagnostic.IDE0074.severity = silent # Requires C# 8 +dotnet_diagnostic.IDE0074.severity = silent # Requires C# 8 - TODO Consider enabling # IDE0056 Use index operator #csharp_style_prefer_index_operator = true -dotnet_diagnostic.IDE0056.severity = silent # Requires C# 8 +dotnet_diagnostic.IDE0056.severity = silent # Requires C# 8 - TODO Consider enabling # IDE0057 Use range operator #csharp_style_prefer_range_operator = true -dotnet_diagnostic.IDE0057.severity = silent # Requires C# 8 +dotnet_diagnostic.IDE0057.severity = silent # Requires C# 8 - TODO Consider enabling # IDE0070 Use 'System.HashCode.Combine' # No options @@ -169,7 +169,7 @@ dotnet_diagnostic.IDE0082.severity = warning # IDE0090 Simplify 'new' expression #csharp_style_implicit_object_creation_when_type_is_apparent = true -dotnet_diagnostic.IDE0090.severity = silent # Requires C# 9 +dotnet_diagnostic.IDE0090.severity = silent # Requires C# 9 - TODO Consider enabling # IDE0180 Use tuple to swap values #csharp_style_prefer_tuple_swap = true @@ -204,7 +204,7 @@ dotnet_diagnostic.IDE0041.severity = warning # IDE0150 Prefer 'null' check over type check #csharp_style_prefer_null_check_over_type_check = true -dotnet_diagnostic.IDE0150.severity = silent # Requires C# 9 +dotnet_diagnostic.IDE0150.severity = silent # Requires C# 9 - TODO Consider enabling # IDE1005 Use conditional delegate call csharp_style_conditional_delegate_call = true # true is the default, but the rule is not triggered if this is not specified. @@ -272,11 +272,11 @@ dotnet_diagnostic.IDE0066.severity = silent # IDE0078 Use pattern matching #csharp_style_prefer_pattern_matching = true -dotnet_diagnostic.IDE0078.severity = silent # Requires C# 9 +dotnet_diagnostic.IDE0078.severity = silent # Requires C# 9 - TODO Consider enabling # IDE0083 Use pattern matching ('not' operator) #csharp_style_prefer_not_pattern = true -dotnet_diagnostic.IDE0083.severity = silent # Requires C# 9 +dotnet_diagnostic.IDE0083.severity = silent # Requires C# 9 - TODO Consider enabling # IDE0170 Simplify property pattern #csharp_style_prefer_extended_property_pattern = true @@ -291,7 +291,7 @@ dotnet_diagnostic.IDE0011.severity = none # IDE0063 Use simple 'using' statement #csharp_prefer_simple_using_statement = true -dotnet_diagnostic.IDE0063.severity = silent # Requires C# 8 +dotnet_diagnostic.IDE0063.severity = silent # Requires C# 8 - TODO Consider enabling ## 'using' directive preferences @@ -375,7 +375,7 @@ dotnet_diagnostic.IDE0100.severity = warning # IDE0110 Remove unnecessary discard # No options -dotnet_diagnostic.IDE0110.severity = silent # Requires C# 9 +dotnet_diagnostic.IDE0110.severity = silent # Requires C# 9 - TODO Consider enabling ### Miscellaneous Rules ### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/miscellaneous-rules @@ -598,6 +598,11 @@ dotnet_diagnostic.SA1633.severity = none # FileMustHaveHeader dotnet_diagnostic.SA1642.severity = none # ConstructorSummaryDocumentationShouldBeginWithStandardText dotnet_diagnostic.SA1649.severity = none # FileNameMustMatchTypeName +# Requires C# 8/9 - TODO Consider enabling +dotnet_diagnostic.SA1141.severity = none # UseTupleSyntax +dotnet_diagnostic.SA1316.severity = none # TupleElementNamesShouldUseCorrectCasing +dotnet_diagnostic.SA1414.severity = none # TupleTypesInSignaturesShouldHaveElementNames + #### Code Quality Rules #### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ @@ -615,8 +620,8 @@ dotnet_diagnostic.CA1827.severity = warning # Use Length/Count property instead of Enumerable.Count method. dotnet_diagnostic.CA1829.severity = warning -# Use span-based 'string.Concat' (incompatible with mono builds). -dotnet_diagnostic.CA1845.severity = none +# Use span-based 'string.Concat'. +dotnet_diagnostic.CA1845.severity = silent # TODO Consider enabling # Use string.Contains(char) instead of string.Contains(string) with single characters. dotnet_diagnostic.CA1847.severity = warning diff --git a/Directory.Build.props b/Directory.Build.props index a2a2f1960f34..47a24e1897fa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ true true true - 7.3 + 9 true .. $(EngineRootPath)/bin @@ -51,7 +51,6 @@ - - + diff --git a/INSTALL.md b/INSTALL.md index 722ddabe8acd..3c2315e056d3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,7 +17,7 @@ Run the game with `launch-game.cmd`. It can be handed arguments that specify the Linux ===== -.NET 6 or Mono (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project. +.NET 6 or Mono (version 6.12 or later) is required to compile OpenRA. We recommend using .NET 6 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project. The [.NET 6 download page](https://dotnet.microsoft.com/download/dotnet/6.0) provides repositories for various package managers and binary releases for several architectures. If you prefer to use Mono, we suggest adding the [upstream repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version and the `msbuild` toolchain. @@ -78,6 +78,6 @@ Type `sudo make install` for system-wide installation. Run `sudo make install-li macOS ===== -[.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 unless you are running a very old version of macOS (10.9 through 10.14). +[.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.12 or later) is required to compile OpenRA. We recommend using .NET 6 unless you are running a very old version of macOS (10.9 through 10.14). To compile OpenRA, run `make` from the command line (or `make RUNTIME=mono` if using Mono). Run with `./launch-game.sh`. diff --git a/Makefile b/Makefile index 8c31c209c1e7..7e8ceea556a4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # to compile, run: # make # -# to compile using Mono (version 6.4 or greater) instead of .NET 6, run: +# to compile using Mono (version 6.12 or greater) instead of .NET 6, run: # make RUNTIME=mono # # to compile using system libraries for native dependencies, run: @@ -92,7 +92,7 @@ endif all: @echo "Compiling in ${CONFIGURATION} mode..." ifeq ($(RUNTIME), mono) - @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 6.4."; exit 1) + @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 6.12."; exit 1) @$(MSBUILD) -t:Build -restore -p:Configuration=${CONFIGURATION} -p:TargetPlatform=$(TARGETPLATFORM) else @$(DOTNET) build -c ${CONFIGURATION} -nologo -p:TargetPlatform=$(TARGETPLATFORM) @@ -173,7 +173,7 @@ help: @echo 'to compile, run:' @echo ' make' @echo - @echo 'to compile using Mono (version 6.4 or greater) instead of .NET 6, run:' + @echo 'to compile using Mono (version 6.12 or greater) instead of .NET 6, run:' @echo ' make RUNTIME=mono' @echo @echo 'to compile using system libraries for native dependencies, run:' diff --git a/OpenRA.Game/Exts.cs b/OpenRA.Game/Exts.cs index 566a361cd92e..b9f4ab325b4f 100644 --- a/OpenRA.Game/Exts.cs +++ b/OpenRA.Game/Exts.cs @@ -149,7 +149,7 @@ public static T RandomOrDefault(this IEnumerable ts, MersenneTwister r) static T Random(IEnumerable ts, MersenneTwister r, bool throws) { var xs = ts as ICollection; - xs = xs ?? ts.ToList(); + xs ??= ts.ToList(); if (xs.Count == 0) { if (throws) @@ -396,8 +396,8 @@ public static Dictionary ToDictionaryWithConflictLog logKey = null, Func logValue = null) { // Fall back on ToString() if null functions are provided: - logKey = logKey ?? (s => s.ToString()); - logValue = logValue ?? (s => s.ToString()); + logKey ??= s => s.ToString(); + logValue ??= s => s.ToString(); // Try to build a dictionary and log all duplicates found (if any): var dupKeys = new Dictionary>(); diff --git a/OpenRA.Mods.Common/Activities/Move/Move.cs b/OpenRA.Mods.Common/Activities/Move/Move.cs index 10f70a395014..2a61b11fb8f1 100644 --- a/OpenRA.Mods.Common/Activities/Move/Move.cs +++ b/OpenRA.Mods.Common/Activities/Move/Move.cs @@ -116,7 +116,7 @@ protected override void OnFirstRun(Actor self) if (evaluateNearestMovableCell && destination.HasValue) { var movableDestination = mobile.NearestMoveableCell(destination.Value); - destination = mobile.CanEnterCell(movableDestination, check: BlockedByActor.Immovable) ? movableDestination : (CPos?)null; + destination = mobile.CanEnterCell(movableDestination, check: BlockedByActor.Immovable) ? movableDestination : null; } // TODO: Change this to BlockedByActor.Stationary after improving the local avoidance behaviour diff --git a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs index 1ce1ccc65fe2..31fecb9d1eff 100644 --- a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs +++ b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs @@ -492,7 +492,7 @@ public virtual void ResolveSprites(SpriteCache cache) }); }).ToArray(); - length = length ?? allSprites.Length - start; + length ??= allSprites.Length - start; if (alpha != null) { diff --git a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs index 6bd19dd724e7..3db8904ffec2 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs @@ -68,7 +68,7 @@ public static PathSearch ToTargetCell( else graph = new MapPathGraph(LayerPoolForWorld(world), locomotor, self, world, check, customCost, ignoreActor, laneBias, inReverse); - heuristic = heuristic ?? DefaultCostEstimator(locomotor, target); + heuristic ??= DefaultCostEstimator(locomotor, target); var search = new PathSearch(graph, heuristic, heuristicWeightPercentage, loc => loc == target, recorder); AddInitialCells(world, locomotor, froms, customCost, search); diff --git a/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs index c5a4451128d1..7c396c18f7d2 100644 --- a/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs +++ b/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs @@ -79,7 +79,7 @@ public Actor[] Reinforce(Player owner, string[] actorTypes, CPos[] entryPath, in for (var i = 0; i < actorTypes.Length; i++) { var af = actionFunc != null ? (LuaFunction)actionFunc.CopyReference() : null; - var actor = CreateActor(owner, actorTypes[i], false, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null); + var actor = CreateActor(owner, actorTypes[i], false, entryPath[0], entryPath.Length > 1 ? entryPath[1] : null); actors.Add(actor); var actionDelay = i * interval; @@ -118,7 +118,7 @@ public Actor[] Reinforce(Player owner, string[] actorTypes, CPos[] entryPath, in public LuaTable ReinforceWithTransport(Player owner, string actorType, string[] cargoTypes, CPos[] entryPath, CPos[] exitPath = null, LuaFunction actionFunc = null, LuaFunction exitFunc = null, int dropRange = 3) { - var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null); + var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : null); var cargo = transport.TraitOrDefault(); var passengers = new List(); diff --git a/OpenRA.Mods.Common/Scripting/Properties/RepairableBuildingProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/RepairableBuildingProperties.cs index f90f67ed8343..d87e760a3da5 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/RepairableBuildingProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/RepairableBuildingProperties.cs @@ -29,7 +29,7 @@ public RepairableBuildingProperties(ScriptContext context, Actor self) [Desc("Start repairs on this building. `repairer` can be an allied player.")] public void StartBuildingRepairs(Player repairer = null) { - repairer = repairer ?? Self.Owner; + repairer ??= Self.Owner; if (!rb.Repairers.Contains(repairer)) rb.RepairBuilding(Self, repairer); @@ -38,7 +38,7 @@ public void StartBuildingRepairs(Player repairer = null) [Desc("Stop repairs on this building. `repairer` can be an allied player.")] public void StopBuildingRepairs(Player repairer = null) { - repairer = repairer ?? Self.Owner; + repairer ??= Self.Owner; if (rb.RepairActive && rb.Repairers.Contains(repairer)) rb.RepairBuilding(Self, repairer); diff --git a/OpenRA.Mods.Common/Traits/Cargo.cs b/OpenRA.Mods.Common/Traits/Cargo.cs index a165fef67fa4..10eeee6263ef 100644 --- a/OpenRA.Mods.Common/Traits/Cargo.cs +++ b/OpenRA.Mods.Common/Traits/Cargo.cs @@ -331,7 +331,7 @@ public string VoicePhraseForOrder(Actor self, Order order) public Actor Unload(Actor self, Actor passenger = null) { - passenger = passenger ?? cargo.Last(); + passenger ??= cargo.Last(); if (!cargo.Remove(passenger)) throw new ArgumentException("Attempted to unload an actor that is not a passenger."); diff --git a/OpenRA.Mods.Common/Traits/Turreted.cs b/OpenRA.Mods.Common/Traits/Turreted.cs index 9bba19fecd0f..1f84338f2f27 100644 --- a/OpenRA.Mods.Common/Traits/Turreted.cs +++ b/OpenRA.Mods.Common/Traits/Turreted.cs @@ -71,7 +71,7 @@ public static Func WorldFacingFromInit(IActorInitializer init, TraitInfo if (turretFacingInit != null) { var facing = turretFacingInit.Value; - return bodyFacing != null ? (Func)(() => bodyFacing() + facing) : () => facing; + return bodyFacing != null ? () => bodyFacing() + facing : () => facing; } var dynamicFacingInit = init.GetOrDefault(info); diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs index 4169b7d354a9..c07286d0e5fb 100644 --- a/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs @@ -149,7 +149,7 @@ public override IEnumerable UpdateSequenceNode(ModData modData, MiniYaml continue; resolvedSequenceNode.Value.Nodes = MiniYaml.Merge(new[] { resolvedDefaultsNode.Value.Nodes, resolvedSequenceNode.Value.Nodes }); - resolvedSequenceNode.Value.Value = resolvedSequenceNode.Value.Value ?? resolvedDefaultsNode.Value.Value; + resolvedSequenceNode.Value.Value ??= resolvedDefaultsNode.Value.Value; } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs index 68b060943ed8..e2875b533a3f 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs @@ -101,7 +101,7 @@ void OpenMenuPanel(MenuButtonWidget button, WidgetArgs widgetArgs = null) if (button.DisableWorldSounds) Game.Sound.DisableWorldSounds = true; - widgetArgs = widgetArgs ?? new WidgetArgs(); + widgetArgs ??= new WidgetArgs(); widgetArgs.Add("onExit", () => { if (button.HideIngameUI) diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index c7b188aa2e10..99fadb371874 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -235,7 +235,7 @@ internal LobbyLogic(Widget widget, ModData modData, WorldRenderer worldRenderer, { { "initialMap", modData.MapCache.PickLastModifiedMap(MapVisibility.Lobby) ?? map.Uid }, { "initialTab", MapClassification.System }, - { "onExit", Game.IsHost ? (Action)UpdateSelectedMap : modData.MapCache.UpdateMaps }, + { "onExit", Game.IsHost ? UpdateSelectedMap : modData.MapCache.UpdateMaps }, { "onSelect", Game.IsHost ? onSelect : null }, { "filter", MapVisibility.Lobby }, }); diff --git a/packaging/macos/checkmono.c b/packaging/macos/checkmono.c index 154a6129a04d..708927bb7c65 100644 --- a/packaging/macos/checkmono.c +++ b/packaging/macos/checkmono.c @@ -18,7 +18,7 @@ #include #define SYSTEM_MONO_PATH "/Library/Frameworks/Mono.framework/Versions/Current/" -#define SYSTEM_MONO_MIN_VERSION "6.4" +#define SYSTEM_MONO_MIN_VERSION "6.12" typedef char *(* mono_get_runtime_build_info)(void); diff --git a/packaging/macos/launcher.m b/packaging/macos/launcher.m index 25f2b293e9c5..17d9a3633c38 100644 --- a/packaging/macos/launcher.m +++ b/packaging/macos/launcher.m @@ -13,7 +13,7 @@ #include #define SYSTEM_MONO_PATH @"/Library/Frameworks/Mono.framework/Versions/Current/" -#define SYSTEM_MONO_MIN_VERSION @"6.4" +#define SYSTEM_MONO_MIN_VERSION @"6.12" #define DOTNET_MIN_MACOS_VERSION 10.15 @interface OpenRALauncher : NSObject diff --git a/packaging/macos/utility.m b/packaging/macos/utility.m index 35636ba6a4b4..45f1121ad58c 100644 --- a/packaging/macos/utility.m +++ b/packaging/macos/utility.m @@ -16,7 +16,7 @@ #include #define SYSTEM_MONO_PATH @"/Library/Frameworks/Mono.framework/Versions/Current/" -#define SYSTEM_MONO_MIN_VERSION @"6.4" +#define SYSTEM_MONO_MIN_VERSION @"6.12" #define DOTNET_MIN_MACOS_VERSION 10.15 typedef void* hostfxr_handle;