Code cleanup (#2439)

* Use new Lock objects

* Fix CA1513: Use ObjectDisposedException.ThrowIf

* Fix CA1860: Avoid using 'Enumerable.Any()' extension method

* Fix IDE0028: Use collection initializers or expressions

* Fix CA2263: Prefer generic overload when type is known

* Fix CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons

* Fix IDE0270: Null check can be simplified

* Fix IDE0280: Use 'nameof'

* Fix IDE0009: Add '.this'

* Fix IDE0007: Use 'var' instead of explicit type

* Fix IDE0062: Make local function static

* Fix CA1859: Use concrete types when possible for improved performance

* Fix IDE0066: Use switch expression

Only applied to where it doesn't look horrendous.

* Use is over switch

* Fix CA1847: Use String.Contains(char) instead of String.Contains(string) with single characters

* Fix SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time.

* Fix CA1866: Use 'string.EndsWith(char)' instead of 'string.EndsWith(string)' when you have a string with a single char

* Fix IDE0057: Substring can be simplified

* Fix IDE0059: Remove unnecessary value assignment

* Fix CA1510: Use ArgumentNullException throw helper

* Fix IDE0300: Use collection expression for array

* Fix IDE0250: Struct can be made 'readonly'

* Fix IDE0018: Inline variable declaration

* Fix CA1850: Prefer static HashData method over ComputeHash

* Fi CA1872: Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString'

* Update ModuleLog instantiations

* Organize usings
This commit is contained in:
Haselnussbomber 2026-01-06 17:36:55 +01:00 committed by GitHub
parent 27414d33dd
commit c93f04f0e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
295 changed files with 830 additions and 932 deletions

View file

@ -342,7 +342,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
{
var mi = this.configs.GetType().GetMethod("LoadForType");
var fn = mi.MakeGenericMethod(type);
return (IPluginConfiguration)fn.Invoke(this.configs, new object[] { this.plugin.InternalName });
return (IPluginConfiguration)fn.Invoke(this.configs, [this.plugin.InternalName]);
}
}

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Bindings.ImGui;
using Dalamud.Configuration.Internal;
using Dalamud.Console;
@ -32,7 +33,7 @@ namespace Dalamud.Plugin.Internal.AutoUpdate;
[ServiceManager.EarlyLoadedService]
internal class AutoUpdateManager : IServiceType
{
private static readonly ModuleLog Log = new("AUTOUPDATE");
private static readonly ModuleLog Log = ModuleLog.Create<AutoUpdateManager>();
/// <summary>
/// Time we should wait after login to update.
@ -376,7 +377,7 @@ internal class AutoUpdateManager : IServiceType
}
}
private void NotifyUpdatesAreAvailable(ICollection<AvailablePluginUpdate> updatablePlugins)
private void NotifyUpdatesAreAvailable(List<AvailablePluginUpdate> updatablePlugins)
{
if (updatablePlugins.Count == 0)
return;

View file

@ -15,9 +15,9 @@ namespace Dalamud.Plugin.Internal.Loader;
/// </summary>
internal class AssemblyLoadContextBuilder
{
private readonly List<string> additionalProbingPaths = new();
private readonly List<string> resourceProbingPaths = new();
private readonly List<string> resourceProbingSubpaths = new();
private readonly List<string> additionalProbingPaths = [];
private readonly List<string> resourceProbingPaths = [];
private readonly List<string> resourceProbingSubpaths = [];
private readonly Dictionary<string, ManagedLibrary> managedLibraries = new(StringComparer.Ordinal);
private readonly Dictionary<string, NativeLibrary> nativeLibraries = new(StringComparer.Ordinal);
private readonly HashSet<string> privateAssemblies = new(StringComparer.Ordinal);
@ -140,7 +140,7 @@ internal class AssemblyLoadContextBuilder
return this;
}
var names = new Queue<AssemblyName>(new[] { assemblyName });
var names = new Queue<AssemblyName>([assemblyName]);
while (names.TryDequeue(out var name))
{

View file

@ -39,13 +39,13 @@ internal class LoaderConfig
/// <summary>
/// Gets a list of assemblies which should be treated as private.
/// </summary>
public ICollection<AssemblyName> PrivateAssemblies { get; } = new List<AssemblyName>();
public ICollection<AssemblyName> PrivateAssemblies { get; } = [];
/// <summary>
/// Gets a list of assemblies which should be unified between the host and the plugin.
/// </summary>
/// <seealso href="https://github.com/natemcmaster/DotNetCorePlugins/blob/main/docs/what-are-shared-types.md">what-are-shared-types</seealso>
public ICollection<(AssemblyName Name, bool Recursive)> SharedAssemblies { get; } = new List<(AssemblyName Name, bool Recursive)>();
public ICollection<(AssemblyName Name, bool Recursive)> SharedAssemblies { get; } = [];
/// <summary>
/// Gets or sets a value indicating whether attempt to unify all types from a plugin with the host.

View file

@ -24,7 +24,7 @@ internal class ManagedLoadContext : AssemblyLoadContext
private readonly IReadOnlyDictionary<string, ManagedLibrary> managedAssemblies;
private readonly IReadOnlyDictionary<string, NativeLibrary> nativeLibraries;
private readonly IReadOnlyCollection<string> privateAssemblies;
private readonly ICollection<string> defaultAssemblies;
private readonly List<string> defaultAssemblies;
private readonly IReadOnlyCollection<string> additionalProbingPaths;
private readonly bool preferDefaultLoadContext;
private readonly string[] resourceRoots;
@ -64,8 +64,7 @@ internal class ManagedLoadContext : AssemblyLoadContext
bool shadowCopyNativeLibraries)
: base(Path.GetFileNameWithoutExtension(mainAssemblyPath), isCollectible)
{
if (resourceProbingPaths == null)
throw new ArgumentNullException(nameof(resourceProbingPaths));
ArgumentNullException.ThrowIfNull(resourceProbingPaths);
this.mainAssemblyPath = mainAssemblyPath ?? throw new ArgumentNullException(nameof(mainAssemblyPath));
this.dependencyResolver = new AssemblyDependencyResolver(mainAssemblyPath);
@ -243,7 +242,7 @@ internal class ManagedLoadContext : AssemblyLoadContext
}
// check to see if there is a library entry for the library without the file extension
var trimmedName = unmanagedDllName.Substring(0, unmanagedDllName.Length - suffix.Length);
var trimmedName = unmanagedDllName[..^suffix.Length];
if (this.nativeLibraries.TryGetValue(prefix + trimmedName, out library))
{

View file

@ -11,21 +11,21 @@ internal class PlatformInformation
/// <summary>
/// Gets a list of native OS specific library extensions.
/// </summary>
public static string[] NativeLibraryExtensions => new[] { ".dll" };
public static string[] NativeLibraryExtensions => [".dll"];
/// <summary>
/// Gets a list of native OS specific library prefixes.
/// </summary>
public static string[] NativeLibraryPrefixes => new[] { string.Empty };
public static string[] NativeLibraryPrefixes => [string.Empty];
/// <summary>
/// Gets a list of native OS specific managed assembly extensions.
/// </summary>
public static string[] ManagedAssemblyExtensions => new[]
{
public static string[] ManagedAssemblyExtensions =>
[
".dll",
".ni.dll",
".exe",
".ni.exe",
};
];
}

View file

@ -53,8 +53,7 @@ internal class PluginLoader : IDisposable
/// <returns>A loader.</returns>
public static PluginLoader CreateFromAssemblyFile(string assemblyFile, Action<LoaderConfig> configure)
{
if (configure == null)
throw new ArgumentNullException(nameof(configure));
ArgumentNullException.ThrowIfNull(configure);
var config = new LoaderConfig(assemblyFile);
configure(config);
@ -159,7 +158,6 @@ internal class PluginLoader : IDisposable
private void EnsureNotDisposed()
{
if (this.disposed)
throw new ObjectDisposedException(nameof(PluginLoader));
ObjectDisposedException.ThrowIf(this.disposed, this);
}
}

View file

@ -22,7 +22,7 @@ internal class PluginErrorHandler : IServiceType
private readonly NotificationManager notificationManager;
private readonly DalamudInterface di;
private readonly Dictionary<Type, Delegate> invokerCache = new();
private readonly Dictionary<Type, Delegate> invokerCache = [];
private DateTime lastErrorTime = DateTime.MinValue;
private IActiveNotification? activeNotification;
@ -141,10 +141,7 @@ internal class PluginErrorHandler : IServiceType
private static Action<TDelegate, object[]> CreateInvoker<TDelegate>() where TDelegate : Delegate
{
var delegateType = typeof(TDelegate);
var method = delegateType.GetMethod("Invoke");
if (method == null)
throw new InvalidOperationException($"Delegate {delegateType} does not have an Invoke method.");
var method = delegateType.GetMethod("Invoke") ?? throw new InvalidOperationException($"Delegate {delegateType} does not have an Invoke method.");
var parameters = method.GetParameters();
// Create parameters for the lambda
@ -153,7 +150,7 @@ internal class PluginErrorHandler : IServiceType
// Create expressions to convert array elements to parameter types
var callArgs = new Expression[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
for (var i = 0; i < parameters.Length; i++)
{
var paramType = parameters[i].ParameterType;
var arrayAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i));

View file

@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Game;
@ -31,6 +32,7 @@ using Dalamud.Plugin.Ipc.Internal;
using Dalamud.Support;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
using Newtonsoft.Json;
namespace Dalamud.Plugin.Internal;
@ -56,9 +58,9 @@ internal class PluginManager : IInternalDisposableService
private readonly DirectoryInfo pluginDirectory;
private readonly BannedPlugin[]? bannedPlugins;
private readonly List<LocalPlugin> installedPluginsList = new();
private readonly List<RemotePluginManifest> availablePluginsList = new();
private readonly List<AvailablePluginUpdate> updatablePluginsList = new();
private readonly List<LocalPlugin> installedPluginsList = [];
private readonly List<RemotePluginManifest> availablePluginsList = [];
private readonly List<AvailablePluginUpdate> updatablePluginsList = [];
private readonly Task<DalamudLinkPayload> openInstallerWindowPluginChangelogsLink;
@ -131,7 +133,7 @@ internal class PluginManager : IInternalDisposableService
PluginInstallerOpenKind.Changelogs);
}));
this.configuration.PluginTestingOptIns ??= new();
this.configuration.PluginTestingOptIns ??= [];
this.MainRepo = PluginRepository.CreateMainRepo(this.happyHttpClient);
registerStartupBlocker(
@ -230,7 +232,7 @@ internal class PluginManager : IInternalDisposableService
/// <summary>
/// Gets a list of all plugin repositories. The main repo should always be first.
/// </summary>
public List<PluginRepository> Repos { get; private set; } = new();
public List<PluginRepository> Repos { get; private set; } = [];
/// <summary>
/// Gets a value indicating whether plugins are not still loading from boot.
@ -1514,11 +1516,7 @@ internal class PluginManager : IInternalDisposableService
JsonConvert.SerializeObject(repoManifest, Formatting.Indented));
// Reload as a local manifest, add some attributes, and save again.
var tempManifest = LocalPluginManifest.Load(tempManifestFile);
if (tempManifest == null)
throw new Exception("Plugin had no valid manifest");
var tempManifest = LocalPluginManifest.Load(tempManifestFile) ?? throw new Exception("Plugin had no valid manifest");
if (tempManifest.InternalName != repoManifest.InternalName)
{
throw new Exception(
@ -1897,9 +1895,9 @@ internal class PluginManager : IInternalDisposableService
/// </summary>
public class StartupLoadTracker
{
private readonly Dictionary<string, string> internalToPublic = new();
private readonly ConcurrentBag<string> allInternalNames = new();
private readonly ConcurrentBag<string> finishedInternalNames = new();
private readonly Dictionary<string, string> internalToPublic = [];
private readonly ConcurrentBag<string> allInternalNames = [];
private readonly ConcurrentBag<string> finishedInternalNames = [];
/// <summary>
/// Gets a value indicating the total load progress.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.Command;
@ -11,7 +11,7 @@ namespace Dalamud.Plugin.Internal;
/// </summary>
internal static class PluginValidator
{
private static readonly char[] LineSeparator = new[] { ' ', '\n', '\r' };
private static readonly char[] LineSeparator = [' ', '\n', '\r'];
/// <summary>
/// Represents the severity of a validation problem.

View file

@ -3,12 +3,14 @@ using System.Linq;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Game;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Serilog;
namespace Dalamud.Plugin.Internal.Profiles;
@ -39,7 +41,7 @@ internal class PluginManagementCommandHandler : IInternalDisposableService
private readonly ChatGui chat;
private readonly Framework framework;
private List<(Target Target, PluginCommandOperation Operation)> commandQueue = new();
private List<(Target Target, PluginCommandOperation Operation)> commandQueue = [];
/// <summary>
/// Initializes a new instance of the <see cref="PluginManagementCommandHandler"/> class.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
@ -14,7 +14,7 @@ namespace Dalamud.Plugin.Internal.Profiles;
/// </summary>
internal class Profile
{
private static readonly ModuleLog Log = new("PROFILE");
private static readonly ModuleLog Log = ModuleLog.Create<Profile>();
private readonly ProfileManager manager;
private readonly ProfileModelV1 modelV1;

View file

@ -1,10 +1,11 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Utility;
@ -15,12 +16,12 @@ namespace Dalamud.Plugin.Internal.Profiles;
/// Class responsible for managing plugin profiles.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService($"Data provider for {nameof(PluginManager)}.")]
internal class ProfileManager : IServiceType
internal partial class ProfileManager : IServiceType
{
private static readonly ModuleLog Log = new("PROFMAN");
private static readonly ModuleLog Log = ModuleLog.Create<ProfileManager>();
private readonly DalamudConfiguration config;
private readonly List<Profile> profiles = new();
private readonly List<Profile> profiles = [];
private volatile bool isBusy = false;
@ -151,11 +152,7 @@ internal class ProfileManager : IServiceType
/// <returns>The newly cloned profile.</returns>
public Profile CloneProfile(Profile toClone)
{
var newProfile = this.ImportProfile(toClone.Model.SerializeForShare());
if (newProfile == null)
throw new Exception("New profile was null while cloning");
return newProfile;
return this.ImportProfile(toClone.Model.SerializeForShare()) ?? throw new Exception("New profile was null while cloning");
}
/// <summary>
@ -338,12 +335,15 @@ internal class ProfileManager : IServiceType
}
}
[GeneratedRegex(@" \(.* Mix\)")]
private static partial Regex MixRegex();
private string GenerateUniqueProfileName(string startingWith)
{
if (this.profiles.All(x => x.Name != startingWith))
return startingWith;
startingWith = Regex.Replace(startingWith, @" \(.* Mix\)", string.Empty);
startingWith = MixRegex().Replace(startingWith, string.Empty);
while (true)
{
@ -359,7 +359,7 @@ internal class ProfileManager : IServiceType
this.config.DefaultProfile ??= new ProfileModelV1();
this.profiles.Add(new Profile(this, this.config.DefaultProfile, true, true));
this.config.SavedProfiles ??= new List<ProfileModel>();
this.config.SavedProfiles ??= [];
foreach (var profileModel in this.config.SavedProfiles)
{
this.profiles.Add(new Profile(this, profileModel, false, true));

View file

@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Reflection;
using Dalamud.Utility;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@ -32,7 +33,7 @@ public abstract class ProfileModel
/// <exception cref="ArgumentException">Thrown when the parsed string is not a valid profile.</exception>
public static ProfileModel? Deserialize(string model)
{
var json = Util.DecompressString(Convert.FromBase64String(model.Substring(3)));
var json = Util.DecompressString(Convert.FromBase64String(model[3..]));
if (model.StartsWith(ProfileModelV1.SerializedPrefix))
return JsonConvert.DeserializeObject<ProfileModelV1>(json);
@ -47,19 +48,15 @@ public abstract class ProfileModel
/// <exception cref="ArgumentOutOfRangeException">Thrown when an unsupported model is serialized.</exception>
public string SerializeForShare()
{
string prefix;
switch (this)
var prefix = this switch
{
case ProfileModelV1:
prefix = ProfileModelV1.SerializedPrefix;
break;
default:
throw new ArgumentOutOfRangeException();
}
ProfileModelV1 => ProfileModelV1.SerializedPrefix,
_ => throw new ArgumentOutOfRangeException(),
};
// HACK: Just filter the ID for now, we should split the sharing + saving model
var serialized = JsonConvert.SerializeObject(this, new JsonSerializerSettings()
{ ContractResolver = new IgnorePropertiesResolver(new[] { "WorkingPluginId" }) });
{ ContractResolver = new IgnorePropertiesResolver(["WorkingPluginId"]) });
return prefix + Convert.ToBase64String(Util.CompressString(serialized));
}

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Newtonsoft.Json;
@ -63,7 +63,7 @@ public class ProfileModelV1 : ProfileModel
/// <summary>
/// Gets or sets the list of plugins in this profile.
/// </summary>
public List<ProfileModelV1Plugin> Plugins { get; set; } = new();
public List<ProfileModelV1Plugin> Plugins { get; set; } = [];
/// <summary>
/// Class representing a single plugin in a profile.

View file

@ -17,7 +17,7 @@ namespace Dalamud.Plugin.Internal.Types;
/// </summary>
internal sealed class LocalDevPlugin : LocalPlugin
{
private static readonly ModuleLog Log = new("PLUGIN");
private static readonly ModuleLog Log = ModuleLog.Create<LocalDevPlugin>();
// Ref to Dalamud.Configuration.DevPluginSettings
private readonly DevPluginSettings devSettings;

View file

@ -33,7 +33,7 @@ internal class LocalPlugin : IAsyncDisposable
protected LocalPluginManifest manifest;
#pragma warning restore SA1401
private static readonly ModuleLog Log = new("LOCALPLUGIN");
private static readonly ModuleLog Log = ModuleLog.Create<LocalPlugin>();
private readonly FileInfo manifestFile;
private readonly FileInfo disabledFile;

View file

@ -1,7 +1,9 @@
using System.IO;
using Dalamud.Utility;
using Newtonsoft.Json;
using Serilog;
namespace Dalamud.Plugin.Internal.Types.Manifest;

View file

@ -1,4 +1,5 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace Dalamud.Plugin.Internal.Types.Manifest;

View file

@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Internal.Types;
/// <summary>
/// Plugin Definition.
/// </summary>
internal struct PluginDef
internal readonly struct PluginDef
{
/// <summary>
/// Initializes a new instance of the <see cref="PluginDef"/> struct.

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using Dalamud.Common.Game;
using Dalamud.Plugin.Internal.Types.Manifest;
using Newtonsoft.Json;
namespace Dalamud.Plugin.Internal.Types;

View file

@ -29,7 +29,7 @@ internal class PluginRepository
private const int HttpRequestTimeoutSeconds = 20;
private static readonly ModuleLog Log = new("PLUGINR");
private static readonly ModuleLog Log = ModuleLog.Create<PluginRepository>();
private readonly HttpClient httpClient;
/// <summary>
@ -119,13 +119,7 @@ internal class PluginRepository
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
var pluginMaster = JsonConvert.DeserializeObject<List<RemotePluginManifest>>(data);
if (pluginMaster == null)
{
throw new Exception("Deserialized PluginMaster was null.");
}
var pluginMaster = JsonConvert.DeserializeObject<List<RemotePluginManifest>>(data) ?? throw new Exception("Deserialized PluginMaster was null.");
pluginMaster.Sort((pm1, pm2) => string.Compare(pm1.Name, pm2.Name, StringComparison.Ordinal));
// Set the source for each remote manifest. Allows for checking if is 3rd party.

View file

@ -1,5 +1,4 @@
using Dalamud.Plugin.Ipc.Internal;
using Dalamud.Utility;
#pragma warning disable SA1402 // File may only contain a single type

View file

@ -9,7 +9,7 @@ namespace Dalamud.Plugin.Ipc.Internal;
[ServiceManager.EarlyLoadedService]
internal class CallGate : IServiceType
{
private readonly Dictionary<string, CallGateChannel> gates = new();
private readonly Dictionary<string, CallGateChannel> gates = [];
private ImmutableDictionary<string, CallGateChannel>? gatesCopy;

View file

@ -9,6 +9,7 @@ using Dalamud.Plugin.Ipc.Exceptions;
using Dalamud.Plugin.Ipc.Internal.Converters;
using Newtonsoft.Json;
using Serilog;
namespace Dalamud.Plugin.Ipc.Internal;
@ -23,7 +24,7 @@ internal class CallGateChannel
/// <summary>
/// The actual storage.
/// </summary>
private readonly HashSet<Delegate> subscriptions = new();
private readonly HashSet<Delegate> subscriptions = [];
/// <summary>
/// A copy of the actual storage, that will be cleared and populated depending on changes made to

View file

@ -40,7 +40,7 @@ internal readonly struct DataCache
{
this.Tag = tag;
this.CreatorAssemblyName = creatorAssemblyName;
this.UserAssemblyNames = new();
this.UserAssemblyNames = [];
this.Data = data;
this.Type = type;
}

View file

@ -19,7 +19,7 @@ internal class DataShare : IServiceType
/// Dictionary of cached values. Note that <see cref="Lazy{T}"/> is being used, as it does its own locking,
/// effectively preventing calling the data generator multiple times concurrently.
/// </summary>
private readonly Dictionary<string, Lazy<DataCache>> caches = new();
private readonly Dictionary<string, Lazy<DataCache>> caches = [];
[ServiceManager.ServiceConstructor]
private DataShare()