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