diff --git a/.globalconfig b/.globalconfig index d6c657bad0..e218f46cd2 100644 --- a/.globalconfig +++ b/.globalconfig @@ -50,6 +50,22 @@ dotnet_diagnostic.IDE1006.severity = warning # Too many noisy warnings for parsing/formatting numbers dotnet_diagnostic.CA1305.severity = none +# CA1806: Do not ignore method results +# The usages for numeric parsing are explicitly optional +dotnet_diagnostic.CA1806.severity = suggestion + +# CA1822: Mark members as static +# Potential false positive around reflection/too much noise +dotnet_diagnostic.CA1822.severity = none + +# CA1859: Use concrete types when possible for improved performance +# Involves design considerations +dotnet_diagnostic.CA1859.severity = none + +# CA1861: Avoid constant arrays as arguments +# Outdated with collection expressions +dotnet_diagnostic.CA1861.severity = none + # CA2007: Consider calling ConfigureAwait on the awaited task dotnet_diagnostic.CA2007.severity = warning diff --git a/Directory.Build.props b/Directory.Build.props index 7cd02a72d4..0f982d496e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -27,6 +27,7 @@ Recommended Recommended Default + Minimum true diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 95ae4c5e80..d88741ec0c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -198,7 +198,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("make second user host", () => MultiplayerClient.TransferHost(3)); - AddUntilStep("kick buttons not visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 0); + AddUntilStep("kick buttons not visible", () => !this.ChildrenOfType().Any(d => d.IsPresent)); AddStep("make local user host again", () => MultiplayerClient.TransferHost(API.LocalUser.Value.Id)); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index e2fe10fa74..f7bdda6b57 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("click delete option", () => { - InputManager.MoveMouseTo(contextMenuContainer.ChildrenOfType().First(i => i.Item.Text.Value.ToString().ToLowerInvariant() == "delete")); + InputManager.MoveMouseTo(contextMenuContainer.ChildrenOfType().First(i => string.Equals(i.Item.Text.Value.ToString(), "delete", System.StringComparison.OrdinalIgnoreCase))); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game/Extensions/StringDehumanizeExtensions.cs b/osu.Game/Extensions/StringDehumanizeExtensions.cs index 6f0d7622d3..5993f83b55 100644 --- a/osu.Game/Extensions/StringDehumanizeExtensions.cs +++ b/osu.Game/Extensions/StringDehumanizeExtensions.cs @@ -60,7 +60,7 @@ namespace osu.Game.Extensions public static string ToCamelCase(this string input) { string word = input.ToPascalCase(); - return word.Length > 0 ? word.Substring(0, 1).ToLowerInvariant() + word.Substring(1) : word; + return word.Length > 0 ? char.ToLowerInvariant(word[0]) + word.Substring(1) : word; } /// diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index fc0060d86a..39860b5e03 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -120,10 +120,9 @@ namespace osu.Game.Overlays.Chat.ChannelList public void RemoveChannel(Channel channel) { - if (!channelMap.ContainsKey(channel)) + if (!channelMap.TryGetValue(channel, out var item)) return; - ChannelListItem item = channelMap[channel]; FillFlowContainer flow = getFlowForChannel(channel); channelMap.Remove(channel); @@ -132,13 +131,7 @@ namespace osu.Game.Overlays.Chat.ChannelList updateVisibility(); } - public ChannelListItem GetItem(Channel channel) - { - if (!channelMap.ContainsKey(channel)) - throw new ArgumentOutOfRangeException(); - - return channelMap[channel]; - } + public ChannelListItem GetItem(Channel channel) => channelMap[channel]; public void ScrollChannelIntoView(Channel channel) => scroll.ScrollIntoView(GetItem(channel)); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index b11483e678..a00414522d 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -386,9 +386,8 @@ namespace osu.Game.Overlays { channelList.RemoveChannel(channel); - if (loadedChannels.ContainsKey(channel)) + if (loadedChannels.TryGetValue(channel, out var loaded)) { - DrawableChannel loaded = loadedChannels[channel]; loadedChannels.Remove(channel); // DrawableChannel removed from cache must be manually disposed loaded.Dispose(); diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 921c1682f5..5e277357a9 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -244,7 +244,7 @@ namespace osu.Game.Overlays.Comments protected void OnSuccess(CommentBundle response) { commentCounter.Current.Value = response.Total; - newCommentEditor.CommentableMeta.Value = response.CommentableMeta.SingleOrDefault(m => m.Id == id.Value && m.Type == type.Value.ToString().ToSnakeCase().ToLowerInvariant()); + newCommentEditor.CommentableMeta.Value = response.CommentableMeta.SingleOrDefault(m => m.Id == id.Value && string.Equals(m.Type, type.Value.ToString().ToSnakeCase(), StringComparison.OrdinalIgnoreCase)); if (!response.Comments.Any()) { diff --git a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs index 4ca937bf86..fb056b457b 100644 --- a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs +++ b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs @@ -173,10 +173,10 @@ namespace osu.Game.Rulesets.Mods }; drawable.OnRevertResult += (_, result) => { - if (!ratesForRewinding.ContainsKey(result.HitObject)) return; + if (!ratesForRewinding.TryGetValue(result.HitObject, out double rewindValue)) return; if (!shouldProcessResult(result)) return; - recentRates.Insert(0, ratesForRewinding[result.HitObject]); + recentRates.Insert(0, rewindValue); ratesForRewinding.Remove(result.HitObject); recentRates.RemoveAt(recentRates.Count - 1); diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index f8bc0ce112..0162c8017b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Objects.Legacy return PathType.CATMULL; case 'B': - if (input.Length > 1 && int.TryParse(input.Substring(1), out int degree) && degree > 0) + if (input.Length > 1 && int.TryParse(input.AsSpan(1), out int degree) && degree > 0) return PathType.BSpline(degree); return PathType.BEZIER; diff --git a/osu.Game/Screens/Ranking/Statistics/User/OverallRanking.cs b/osu.Game/Screens/Ranking/Statistics/User/OverallRanking.cs index 171a3f0f65..9f5afea6f0 100644 --- a/osu.Game/Screens/Ranking/Statistics/User/OverallRanking.cs +++ b/osu.Game/Screens/Ranking/Statistics/User/OverallRanking.cs @@ -59,14 +59,14 @@ namespace osu.Game.Screens.Ranking.Statistics.User new SimpleStatisticTable.Spacer(), new PerformancePointsChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } }, }, - new Drawable[] { }, + [], new Drawable[] { new MaximumComboChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } }, new SimpleStatisticTable.Spacer(), new AccuracyChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } }, }, - new Drawable[] { }, + [], new Drawable[] { new RankedScoreChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } }, diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 59c7f0ba26..70d3195ecd 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -37,7 +37,7 @@ namespace osu.Game.Skinning protected override string[] HashableFileTypes => new[] { ".ini", ".json" }; - protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path).ToLowerInvariant() == @".osk"; + protected override bool ShouldDeleteArchive(string path) => string.Equals(Path.GetExtension(path), @".osk", StringComparison.OrdinalIgnoreCase); protected override SkinInfo CreateModel(ArchiveReader archive, ImportParameters parameters) => new SkinInfo { Name = archive.Name ?? @"No name" }; diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 8c43b99702..5120757f3d 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -89,7 +90,7 @@ namespace osu.Game.Storyboards // Importantly, do this after the NullOrEmpty because EF may have stored the non-nullable value as null to the database, bypassing compile-time constraints. backgroundPath = backgroundPath.ToLowerInvariant(); - return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath); + return GetLayer("Background").Elements.Any(e => string.Equals(e.Path, backgroundPath, StringComparison.OrdinalIgnoreCase)); } } diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index c27e7f15ca..5d33afd288 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -78,12 +78,12 @@ namespace osu.Game.Tests.Visual.Spectator /// The spectator state to end play with. public void SendEndPlay(int userId, SpectatedUserState state = SpectatedUserState.Quit) { - if (!userBeatmapDictionary.ContainsKey(userId)) + if (!userBeatmapDictionary.TryGetValue(userId, out int beatmapId)) return; ((ISpectatorClient)this).UserFinishedPlaying(userId, new SpectatorState { - BeatmapID = userBeatmapDictionary[userId], + BeatmapID = beatmapId, RulesetID = 0, Mods = userModsDictionary[userId], State = state