Merge pull request #87133 from Repiteo/dotnet/enforce-globalization-rules

C#: Enforce globalization code quality rules
This commit is contained in:
Rémi Verschelde 2024-02-20 20:04:30 +01:00 committed by GitHub
commit 1aab6e96b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 103 additions and 98 deletions

View File

@ -30,14 +30,5 @@ dotnet_diagnostic.CA1720.severity = none
# CA1805: Do not initialize unnecessarily # CA1805: Do not initialize unnecessarily
# Don't tell me what to do. # Don't tell me what to do.
dotnet_diagnostic.CA1805.severity = none dotnet_diagnostic.CA1805.severity = none
# CA1304: Specify CultureInfo
# TODO: We should look into this.
dotnet_diagnostic.CA1304.severity = warning
# CA1305: Specify IFormatProvider
# TODO: We should look into this. Disabled for now because it's annoying.
dotnet_diagnostic.CA1305.severity = none
# CA1310: Specify StringComparison for correctness
# TODO: We should look into this. Disabled for now because it's annoying.
dotnet_diagnostic.CA1310.severity = none
# Diagnostics to prevent defensive copies of `in` struct parameters # Diagnostics to prevent defensive copies of `in` struct parameters
resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error

View File

@ -165,7 +165,7 @@ namespace GodotTools.BuildLogger
bool hasSpecialChar = value.IndexOfAny(new[] { '\"', '\n', '\r', delimiter }) != -1; bool hasSpecialChar = value.IndexOfAny(new[] { '\"', '\n', '\r', delimiter }) != -1;
if (hasSpecialChar) if (hasSpecialChar)
return "\"" + value.Replace("\"", "\"\"") + "\""; return "\"" + value.Replace("\"", "\"\"", StringComparison.Ordinal) + "\"";
return value; return value;
} }

View File

@ -15,7 +15,7 @@ namespace GodotTools.Core
dir = Path.Combine(dir, " ").TrimEnd(); dir = Path.Combine(dir, " ").TrimEnd();
if (Path.DirectorySeparatorChar == '\\') if (Path.DirectorySeparatorChar == '\\')
dir = dir.Replace("/", "\\") + "\\"; dir = dir.Replace("/", "\\", StringComparison.Ordinal) + "\\";
var fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute); var fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
var relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute); var relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);

View File

@ -1,3 +1,4 @@
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -28,7 +29,7 @@ namespace GodotTools.IdeMessaging.CLI
{ {
await outputWriter.WriteLineAsync("======= Request ======="); await outputWriter.WriteLineAsync("======= Request =======");
await outputWriter.WriteLineAsync(id); await outputWriter.WriteLineAsync(id);
await outputWriter.WriteLineAsync(content.Body.Count(c => c == '\n').ToString()); await outputWriter.WriteLineAsync(content.Body.Count(c => c == '\n').ToString(CultureInfo.InvariantCulture));
await outputWriter.WriteLineAsync(content.Body); await outputWriter.WriteLineAsync(content.Body);
await outputWriter.WriteLineAsync("======================="); await outputWriter.WriteLineAsync("=======================");
await outputWriter.FlushAsync(); await outputWriter.FlushAsync();
@ -41,7 +42,7 @@ namespace GodotTools.IdeMessaging.CLI
{ {
await outputWriter.WriteLineAsync("======= Response ======="); await outputWriter.WriteLineAsync("======= Response =======");
await outputWriter.WriteLineAsync(id); await outputWriter.WriteLineAsync(id);
await outputWriter.WriteLineAsync(content.Body.Count(c => c == '\n').ToString()); await outputWriter.WriteLineAsync(content.Body.Count(c => c == '\n').ToString(CultureInfo.InvariantCulture));
await outputWriter.WriteLineAsync(content.Body); await outputWriter.WriteLineAsync(content.Body);
await outputWriter.WriteLineAsync("========================"); await outputWriter.WriteLineAsync("========================");
await outputWriter.FlushAsync(); await outputWriter.FlushAsync();

View File

@ -1,5 +1,7 @@
using GodotTools.Core; using GodotTools.Core;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -92,8 +94,8 @@ EndProject";
if (!isFirstProject) if (!isFirstProject)
projectsDecl += "\n"; projectsDecl += "\n";
projectsDecl += string.Format(_projectDeclaration, projectsDecl += string.Format(CultureInfo.InvariantCulture, _projectDeclaration,
name, projectInfo.PathRelativeToSolution.Replace("/", "\\"), projectInfo.Guid); name, projectInfo.PathRelativeToSolution.Replace("/", "\\", StringComparison.Ordinal), projectInfo.Guid);
for (int i = 0; i < projectInfo.Configs.Count; i++) for (int i = 0; i < projectInfo.Configs.Count; i++)
{ {
@ -105,15 +107,15 @@ EndProject";
projPlatformsCfg += "\n"; projPlatformsCfg += "\n";
} }
slnPlatformsCfg += string.Format(_solutionPlatformsConfig, config); slnPlatformsCfg += string.Format(CultureInfo.InvariantCulture, _solutionPlatformsConfig, config);
projPlatformsCfg += string.Format(_projectPlatformsConfig, projectInfo.Guid, config); projPlatformsCfg += string.Format(CultureInfo.InvariantCulture, _projectPlatformsConfig, projectInfo.Guid, config);
} }
isFirstProject = false; isFirstProject = false;
} }
string solutionPath = Path.Combine(DirectoryPath, Name + ".sln"); string solutionPath = Path.Combine(DirectoryPath, Name + ".sln");
string content = string.Format(_solutionTemplate, projectsDecl, slnPlatformsCfg, projPlatformsCfg); string content = string.Format(CultureInfo.InvariantCulture, _solutionTemplate, projectsDecl, slnPlatformsCfg, projPlatformsCfg);
File.WriteAllText(solutionPath, content, Encoding.UTF8); // UTF-8 with BOM File.WriteAllText(solutionPath, content, Encoding.UTF8); // UTF-8 with BOM
} }

View File

@ -38,21 +38,18 @@ namespace GodotTools.Build
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked var hash = new HashCode();
{ hash.Add(Solution);
int hash = 17; hash.Add(Project);
hash = (hash * 29) + Solution.GetHashCode(); hash.Add(Configuration);
hash = (hash * 29) + Project.GetHashCode(); hash.Add(RuntimeIdentifier);
hash = (hash * 29) + Configuration.GetHashCode(); hash.Add(PublishOutputDir);
hash = (hash * 29) + (RuntimeIdentifier?.GetHashCode() ?? 0); hash.Add(Restore);
hash = (hash * 29) + (PublishOutputDir?.GetHashCode() ?? 0); hash.Add(Rebuild);
hash = (hash * 29) + Restore.GetHashCode(); hash.Add(OnlyClean);
hash = (hash * 29) + Rebuild.GetHashCode(); hash.Add(CustomProperties);
hash = (hash * 29) + OnlyClean.GetHashCode(); hash.Add(LogsDirPath);
hash = (hash * 29) + CustomProperties.GetHashCode(); return hash.ToHashCode();
hash = (hash * 29) + LogsDirPath.GetHashCode();
return hash;
}
} }
// Needed for instantiation from Godot, after reloading assemblies // Needed for instantiation from Godot, after reloading assemblies

View File

@ -1,4 +1,5 @@
using Godot; using Godot;
using System.Globalization;
namespace GodotTools.Build namespace GodotTools.Build
{ {
@ -16,7 +17,7 @@ namespace GodotTools.Build
set set
{ {
_problemsCount = value; _problemsCount = value;
ToggleButton.Text = _problemsCount.ToString(); ToggleButton.Text = _problemsCount.ToString(CultureInfo.InvariantCulture);
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -83,8 +84,8 @@ namespace GodotTools.Build
"error" or _ => BuildDiagnostic.DiagnosticType.Error, "error" or _ => BuildDiagnostic.DiagnosticType.Error,
}, },
File = csvColumns[1], File = csvColumns[1],
Line = int.Parse(csvColumns[2]), Line = int.Parse(csvColumns[2], CultureInfo.InvariantCulture),
Column = int.Parse(csvColumns[3]), Column = int.Parse(csvColumns[3], CultureInfo.InvariantCulture),
Code = csvColumns[4], Code = csvColumns[4],
Message = csvColumns[5], Message = csvColumns[5],
ProjectFile = csvColumns[6], ProjectFile = csvColumns[6],
@ -93,7 +94,7 @@ namespace GodotTools.Build
// If there's no ProjectFile but the File is a csproj, then use that. // If there's no ProjectFile but the File is a csproj, then use that.
if (string.IsNullOrEmpty(diagnostic.ProjectFile) && if (string.IsNullOrEmpty(diagnostic.ProjectFile) &&
!string.IsNullOrEmpty(diagnostic.File) && !string.IsNullOrEmpty(diagnostic.File) &&
diagnostic.File.EndsWith(".csproj")) diagnostic.File.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
{ {
diagnostic.ProjectFile = diagnostic.File; diagnostic.ProjectFile = diagnostic.File;
} }
@ -151,9 +152,9 @@ namespace GodotTools.Build
foreach (var diagnostic in selectedDiagnostics) foreach (var diagnostic in selectedDiagnostics)
{ {
if (!string.IsNullOrEmpty(diagnostic.Code)) if (!string.IsNullOrEmpty(diagnostic.Code))
sb.Append($"{diagnostic.Code}: "); sb.Append(CultureInfo.InvariantCulture, $"{diagnostic.Code}: ");
sb.AppendLine($"{diagnostic.Message} {diagnostic.File}({diagnostic.Line},{diagnostic.Column})"); sb.AppendLine(CultureInfo.InvariantCulture, $"{diagnostic.Message} {diagnostic.File}({diagnostic.Line},{diagnostic.Column})");
} }
string text = sb.ToString(); string text = sb.ToString();
@ -251,7 +252,7 @@ namespace GodotTools.Build
file = ProjectSettings.LocalizePath(file); file = ProjectSettings.LocalizePath(file);
if (file.StartsWith("res://")) if (file.StartsWith("res://", StringComparison.Ordinal))
{ {
var script = (Script)ResourceLoader.Load(file, typeHint: Internal.CSharpLanguageType); var script = (Script)ResourceLoader.Load(file, typeHint: Internal.CSharpLanguageType);
@ -426,7 +427,7 @@ namespace GodotTools.Build
? Path.GetRelativePath(projectDir, file) ? Path.GetRelativePath(projectDir, file)
: "Unknown file".TTR(); : "Unknown file".TTR();
string fileItemText = string.Format("{0} ({1} issues)".TTR(), relativeFilePath, fileDiagnostics.Length); string fileItemText = string.Format(CultureInfo.InvariantCulture, "{0} ({1} issues)".TTR(), relativeFilePath, fileDiagnostics.Length);
var fileItem = _problemsTree.CreateItem(projectItem); var fileItem = _problemsTree.CreateItem(projectItem);
fileItem.SetText(0, fileItemText); fileItem.SetText(0, fileItemText);
@ -468,10 +469,10 @@ namespace GodotTools.Build
shortMessage = shortMessage[..lineBreakIdx]; shortMessage = shortMessage[..lineBreakIdx];
text.Append(shortMessage); text.Append(shortMessage);
tooltip.Append($"Message: {diagnostic.Message}"); tooltip.Append(CultureInfo.InvariantCulture, $"Message: {diagnostic.Message}");
if (!string.IsNullOrEmpty(diagnostic.Code)) if (!string.IsNullOrEmpty(diagnostic.Code))
tooltip.Append($"\nCode: {diagnostic.Code}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nCode: {diagnostic.Code}");
string type = diagnostic.Type switch string type = diagnostic.Type switch
{ {
@ -481,7 +482,7 @@ namespace GodotTools.Build
BuildDiagnostic.DiagnosticType.Error => "error", BuildDiagnostic.DiagnosticType.Error => "error",
_ => "unknown", _ => "unknown",
}; };
tooltip.Append($"\nType: {type}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nType: {type}");
if (!string.IsNullOrEmpty(diagnostic.File)) if (!string.IsNullOrEmpty(diagnostic.File))
{ {
@ -491,15 +492,15 @@ namespace GodotTools.Build
text.Append(diagnostic.File); text.Append(diagnostic.File);
} }
text.Append($"({diagnostic.Line},{diagnostic.Column})"); text.Append(CultureInfo.InvariantCulture, $"({diagnostic.Line},{diagnostic.Column})");
tooltip.Append($"\nFile: {diagnostic.File}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nFile: {diagnostic.File}");
tooltip.Append($"\nLine: {diagnostic.Line}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nLine: {diagnostic.Line}");
tooltip.Append($"\nColumn: {diagnostic.Column}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nColumn: {diagnostic.Column}");
} }
if (!string.IsNullOrEmpty(diagnostic.ProjectFile)) if (!string.IsNullOrEmpty(diagnostic.ProjectFile))
tooltip.Append($"\nProject: {diagnostic.ProjectFile}"); tooltip.Append(CultureInfo.InvariantCulture, $"\nProject: {diagnostic.ProjectFile}");
return new ProblemItem() return new ProblemItem()
{ {

View File

@ -12,6 +12,7 @@ using Directory = GodotTools.Utils.Directory;
using File = GodotTools.Utils.File; using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS; using OS = GodotTools.Utils.OS;
using Path = System.IO.Path; using Path = System.IO.Path;
using System.Globalization;
namespace GodotTools.Export namespace GodotTools.Export
{ {
@ -277,7 +278,7 @@ namespace GodotTools.Export
if (platform == OS.Platforms.iOS) if (platform == OS.Platforms.iOS)
{ {
// Exclude dsym folders. // Exclude dsym folders.
return !dir.EndsWith(".dsym", StringComparison.InvariantCultureIgnoreCase); return !dir.EndsWith(".dsym", StringComparison.OrdinalIgnoreCase);
} }
return true; return true;
@ -297,7 +298,7 @@ namespace GodotTools.Export
if (platform == OS.Platforms.iOS) if (platform == OS.Platforms.iOS)
{ {
// Don't recurse into dsym folders. // Don't recurse into dsym folders.
return !dir.EndsWith(".dsym", StringComparison.InvariantCultureIgnoreCase); return !dir.EndsWith(".dsym", StringComparison.OrdinalIgnoreCase);
} }
return true; return true;
@ -313,13 +314,13 @@ namespace GodotTools.Export
byte[] fileData = File.ReadAllBytes(path); byte[] fileData = File.ReadAllBytes(path);
string hash = Convert.ToBase64String(SHA512.HashData(fileData)); string hash = Convert.ToBase64String(SHA512.HashData(fileData));
manifest.Append($"{filePath}\t{hash}\n"); manifest.Append(CultureInfo.InvariantCulture, $"{filePath}\t{hash}\n");
AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false); AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
} }
else else
{ {
if (platform == OS.Platforms.iOS && path.EndsWith(".dat")) if (platform == OS.Platforms.iOS && path.EndsWith(".dat", StringComparison.OrdinalIgnoreCase))
{ {
AddIosBundleFile(path); AddIosBundleFile(path);
} }

View File

@ -4,6 +4,7 @@ using GodotTools.Export;
using GodotTools.Utils; using GodotTools.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using GodotTools.Build; using GodotTools.Build;
@ -202,10 +203,10 @@ namespace GodotTools
var insideQuotes = false; var insideQuotes = false;
var hasFileFlag = false; var hasFileFlag = false;
execArgs = execArgs.ReplaceN("{line}", line.ToString()); execArgs = execArgs.ReplaceN("{line}", line.ToString(CultureInfo.InvariantCulture));
execArgs = execArgs.ReplaceN("{col}", col.ToString()); execArgs = execArgs.ReplaceN("{col}", col.ToString(CultureInfo.InvariantCulture));
execArgs = execArgs.StripEdges(true, true); execArgs = execArgs.StripEdges(true, true);
execArgs = execArgs.Replace("\\\\", "\\"); execArgs = execArgs.Replace("\\\\", "\\", StringComparison.Ordinal);
for (int i = 0; i < execArgs.Length; ++i) for (int i = 0; i < execArgs.Length; ++i)
{ {
@ -225,7 +226,7 @@ namespace GodotTools
} }
var arg = execArgs.Substr(from, numChars); var arg = execArgs.Substr(from, numChars);
if (arg.Contains("{file}")) if (arg.Contains("{file}", StringComparison.OrdinalIgnoreCase))
{ {
hasFileFlag = true; hasFileFlag = true;
} }

View File

@ -73,7 +73,7 @@ namespace GodotTools.Internals
string? slnParentDir = (string?)ProjectSettings.GetSetting("dotnet/project/solution_directory"); string? slnParentDir = (string?)ProjectSettings.GetSetting("dotnet/project/solution_directory");
if (string.IsNullOrEmpty(slnParentDir)) if (string.IsNullOrEmpty(slnParentDir))
slnParentDir = "res://"; slnParentDir = "res://";
else if (!slnParentDir.StartsWith("res://")) else if (!slnParentDir.StartsWith("res://", System.StringComparison.Ordinal))
slnParentDir = "res://" + slnParentDir; slnParentDir = "res://" + slnParentDir;
// The csproj should be in the same folder as project.godot. // The csproj should be in the same folder as project.godot.

View File

@ -274,7 +274,7 @@ namespace GodotTools.Utils
if (builder.Length > 0) if (builder.Length > 0)
builder.Append(' '); builder.Append(' ');
if (fileName.Contains(' ')) if (fileName.Contains(' ', StringComparison.Ordinal))
{ {
builder.Append('"'); builder.Append('"');
builder.Append(fileName); builder.Append(fileName);
@ -297,7 +297,7 @@ namespace GodotTools.Utils
if (builder.Length > 0) if (builder.Length > 0)
builder.Append(' '); builder.Append(' ');
if (argument.Contains(' ')) if (argument.Contains(' ', StringComparison.Ordinal))
{ {
builder.Append('"'); builder.Append('"');
builder.Append(argument); builder.Append(argument);

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Godot.NativeInterop; using Godot.NativeInterop;
@ -776,11 +777,11 @@ namespace Godot
private static bool FindNamedColor(string name, out Color color) private static bool FindNamedColor(string name, out Color color)
{ {
name = name.Replace(" ", string.Empty); name = name.Replace(" ", string.Empty, StringComparison.Ordinal);
name = name.Replace("-", string.Empty); name = name.Replace("-", string.Empty, StringComparison.Ordinal);
name = name.Replace("_", string.Empty); name = name.Replace("_", string.Empty, StringComparison.Ordinal);
name = name.Replace("'", string.Empty); name = name.Replace("'", string.Empty, StringComparison.Ordinal);
name = name.Replace(".", string.Empty); name = name.Replace(".", string.Empty, StringComparison.Ordinal);
name = name.ToUpperInvariant(); name = name.ToUpperInvariant();
return Colors.namedColors.TryGetValue(name, out color); return Colors.namedColors.TryGetValue(name, out color);
@ -1329,7 +1330,9 @@ namespace Godot
/// <returns>A string representation of this color.</returns> /// <returns>A string representation of this color.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({R.ToString(format)}, {G.ToString(format)}, {B.ToString(format)}, {A.ToString(format)})"; return $"({R.ToString(format)}, {G.ToString(format)}, {B.ToString(format)}, {A.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -698,7 +699,7 @@ namespace Godot
case GodotObject godotObject: case GodotObject godotObject:
return VariantUtils.CreateFrom(godotObject); return VariantUtils.CreateFrom(godotObject);
case Enum @enum: case Enum @enum:
return VariantUtils.CreateFrom(Convert.ToInt64(@enum)); return VariantUtils.CreateFrom(Convert.ToInt64(@enum, CultureInfo.InvariantCulture));
case Collections.IGenericGodotDictionary godotDictionary: case Collections.IGenericGodotDictionary godotDictionary:
return VariantUtils.CreateFrom(godotDictionary.UnderlyingDictionary); return VariantUtils.CreateFrom(godotDictionary.UnderlyingDictionary);
case Collections.IGenericGodotArray godotArray: case Collections.IGenericGodotArray godotArray:
@ -777,7 +778,7 @@ namespace Godot
return func(variant); return func(variant);
if (typeof(GodotObject).IsAssignableFrom(type)) if (typeof(GodotObject).IsAssignableFrom(type))
return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type); return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type, CultureInfo.InvariantCulture);
if (typeof(GodotObject[]).IsAssignableFrom(type)) if (typeof(GodotObject[]).IsAssignableFrom(type))
{ {
@ -796,7 +797,7 @@ namespace Godot
} }
using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant); using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant);
return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type); return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type, CultureInfo.InvariantCulture);
} }
if (type.IsEnum) if (type.IsEnum)

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Globalization;
using System.Text; using System.Text;
#nullable enable #nullable enable
@ -73,7 +74,7 @@ namespace Godot
if (!string.IsNullOrEmpty(_nativeClassName)) if (!string.IsNullOrEmpty(_nativeClassName))
{ {
sb.Append($" (Method '{_nativeClassName}')"); sb.Append(CultureInfo.InvariantCulture, $" (Method '{_nativeClassName}')");
} }
return sb.ToString(); return sb.ToString();
@ -131,7 +132,7 @@ namespace Godot
if (!string.IsNullOrEmpty(_nativeMethodName)) if (!string.IsNullOrEmpty(_nativeMethodName))
{ {
sb.Append($" (Method '{_nativeMethodName}')"); sb.Append(CultureInfo.InvariantCulture, $" (Method '{_nativeMethodName}')");
} }
return sb.ToString(); return sb.ToString();

View File

@ -435,7 +435,9 @@ namespace Godot
/// <returns>A string representation of this plane.</returns> /// <returns>A string representation of this plane.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"{_normal.ToString(format)}, {_d.ToString(format)}"; return $"{_normal.ToString(format)}, {_d.ToString(format)}";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -1023,10 +1023,12 @@ namespace Godot
/// <returns>A string representation of this projection.</returns> /// <returns>A string representation of this projection.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"{X.X.ToString(format)}, {X.Y.ToString(format)}, {X.Z.ToString(format)}, {X.W.ToString(format)}\n" + return $"{X.X.ToString(format)}, {X.Y.ToString(format)}, {X.Z.ToString(format)}, {X.W.ToString(format)}\n" +
$"{Y.X.ToString(format)}, {Y.Y.ToString(format)}, {Y.Z.ToString(format)}, {Y.W.ToString(format)}\n" + $"{Y.X.ToString(format)}, {Y.Y.ToString(format)}, {Y.Z.ToString(format)}, {Y.W.ToString(format)}\n" +
$"{Z.X.ToString(format)}, {Z.Y.ToString(format)}, {Z.Z.ToString(format)}, {Z.W.ToString(format)}\n" + $"{Z.X.ToString(format)}, {Z.Y.ToString(format)}, {Z.Z.ToString(format)}, {Z.W.ToString(format)}\n" +
$"{W.X.ToString(format)}, {W.Y.ToString(format)}, {W.Z.ToString(format)}, {W.W.ToString(format)}\n"; $"{W.X.ToString(format)}, {W.Y.ToString(format)}, {W.Z.ToString(format)}, {W.W.ToString(format)}\n";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -822,7 +822,9 @@ namespace Godot
/// <returns>A string representation of this quaternion.</returns> /// <returns>A string representation of this quaternion.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -314,7 +314,7 @@ namespace Godot
/// <returns>The capitalized string.</returns> /// <returns>The capitalized string.</returns>
public static string Capitalize(this string instance) public static string Capitalize(this string instance)
{ {
string aux = instance.CamelcaseToUnderscore(true).Replace("_", " ").Trim(); string aux = instance.CamelcaseToUnderscore(true).Replace("_", " ", StringComparison.Ordinal).Trim();
string cap = string.Empty; string cap = string.Empty;
for (int i = 0; i < aux.GetSliceCount(" "); i++) for (int i = 0; i < aux.GetSliceCount(" "); i++)
@ -742,7 +742,7 @@ namespace Godot
byte[] ret = new byte[len]; byte[] ret = new byte[len];
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
ret[i] = (byte)int.Parse(instance.AsSpan(i * 2, 2), NumberStyles.AllowHexSpecifier); ret[i] = (byte)int.Parse(instance.AsSpan(i * 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
} }
return ret; return ret;
} }
@ -821,7 +821,7 @@ namespace Godot
instance = instance.Substring(2); instance = instance.Substring(2);
} }
return sign * int.Parse(instance, NumberStyles.HexNumber); return sign * int.Parse(instance, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
} }
/// <summary> /// <summary>
@ -878,7 +878,7 @@ namespace Godot
if (string.IsNullOrEmpty(instance)) if (string.IsNullOrEmpty(instance))
return false; return false;
else if (instance.Length > 1) else if (instance.Length > 1)
return instance[0] == '/' || instance[0] == '\\' || instance.Contains(":/") || instance.Contains(":\\"); return instance[0] == '/' || instance[0] == '\\' || instance.Contains(":/", StringComparison.Ordinal) || instance.Contains(":\\", StringComparison.Ordinal);
else else
return instance[0] == '/' || instance[0] == '\\'; return instance[0] == '/' || instance[0] == '\\';
} }
@ -1120,7 +1120,7 @@ namespace Godot
/// <returns>If the string contains a valid IP address.</returns> /// <returns>If the string contains a valid IP address.</returns>
public static bool IsValidIPAddress(this string instance) public static bool IsValidIPAddress(this string instance)
{ {
if (instance.Contains(':')) if (instance.Contains(':', StringComparison.Ordinal))
{ {
string[] ip = instance.Split(':'); string[] ip = instance.Split(':');
@ -1404,23 +1404,10 @@ namespace Godot
return instance + "/" + file; return instance + "/" + file;
} }
/// <summary>
/// Replace occurrences of a substring for different ones inside the string.
/// </summary>
/// <seealso cref="ReplaceN(string, string, string)"/>
/// <param name="instance">The string to modify.</param>
/// <param name="what">The substring to be replaced in the string.</param>
/// <param name="forwhat">The substring that replaces <paramref name="what"/>.</param>
/// <returns>The string with the substring occurrences replaced.</returns>
public static string Replace(this string instance, string what, string forwhat)
{
return instance.Replace(what, forwhat);
}
/// <summary> /// <summary>
/// Replace occurrences of a substring for different ones inside the string, but search case-insensitive. /// Replace occurrences of a substring for different ones inside the string, but search case-insensitive.
/// </summary> /// </summary>
/// <seealso cref="Replace(string, string, string)"/> /// <seealso cref="string.Replace(string, string, StringComparison)"/>
/// <param name="instance">The string to modify.</param> /// <param name="instance">The string to modify.</param>
/// <param name="what">The substring to be replaced in the string.</param> /// <param name="what">The substring to be replaced in the string.</param>
/// <param name="forwhat">The substring that replaces <paramref name="what"/>.</param> /// <param name="forwhat">The substring that replaces <paramref name="what"/>.</param>
@ -1634,7 +1621,7 @@ namespace Godot
if (end < 0) if (end < 0)
end = len; end = len;
if (allowEmpty || end > from) if (allowEmpty || end > from)
ret.Add(float.Parse(instance.Substring(from))); ret.Add(float.Parse(instance.Substring(from), CultureInfo.InvariantCulture));
if (end == len) if (end == len)
break; break;
@ -1738,7 +1725,7 @@ namespace Godot
/// <returns>The number representation of the string.</returns> /// <returns>The number representation of the string.</returns>
public static float ToFloat(this string instance) public static float ToFloat(this string instance)
{ {
return float.Parse(instance); return float.Parse(instance, CultureInfo.InvariantCulture);
} }
/// <summary> /// <summary>
@ -1749,7 +1736,7 @@ namespace Godot
/// <returns>The number representation of the string.</returns> /// <returns>The number representation of the string.</returns>
public static int ToInt(this string instance) public static int ToInt(this string instance)
{ {
return int.Parse(instance); return int.Parse(instance, CultureInfo.InvariantCulture);
} }
/// <summary> /// <summary>
@ -1802,7 +1789,7 @@ namespace Godot
/// <returns>A copy of the string with the prefix string removed from the start.</returns> /// <returns>A copy of the string with the prefix string removed from the start.</returns>
public static string TrimPrefix(this string instance, string prefix) public static string TrimPrefix(this string instance, string prefix)
{ {
if (instance.StartsWith(prefix)) if (instance.StartsWith(prefix, StringComparison.Ordinal))
return instance.Substring(prefix.Length); return instance.Substring(prefix.Length);
return instance; return instance;
@ -1816,7 +1803,7 @@ namespace Godot
/// <returns>A copy of the string with the suffix string removed from the end.</returns> /// <returns>A copy of the string with the suffix string removed from the end.</returns>
public static string TrimSuffix(this string instance, string suffix) public static string TrimSuffix(this string instance, string suffix)
{ {
if (instance.EndsWith(suffix)) if (instance.EndsWith(suffix, StringComparison.Ordinal))
return instance.Substring(0, instance.Length - suffix.Length); return instance.Substring(0, instance.Length - suffix.Length);
return instance; return instance;
@ -1833,7 +1820,7 @@ namespace Godot
/// <returns>The unescaped string.</returns> /// <returns>The unescaped string.</returns>
public static string URIDecode(this string instance) public static string URIDecode(this string instance)
{ {
return Uri.UnescapeDataString(instance.Replace("+", "%20")); return Uri.UnescapeDataString(instance.Replace("+", "%20", StringComparison.Ordinal));
} }
/// <summary> /// <summary>
@ -1860,10 +1847,10 @@ namespace Godot
/// <returns>The string sanitized as a valid node name.</returns> /// <returns>The string sanitized as a valid node name.</returns>
public static string ValidateNodeName(this string instance) public static string ValidateNodeName(this string instance)
{ {
string name = instance.Replace(_invalidNodeNameCharacters[0], ""); string name = instance.Replace(_invalidNodeNameCharacters[0], "", StringComparison.Ordinal);
for (int i = 1; i < _invalidNodeNameCharacters.Length; i++) for (int i = 1; i < _invalidNodeNameCharacters.Length; i++)
{ {
name = name.Replace(_invalidNodeNameCharacters[i], ""); name = name.Replace(_invalidNodeNameCharacters[i], "", StringComparison.Ordinal);
} }
return name; return name;
} }

View File

@ -1021,7 +1021,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -600,7 +600,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -1123,7 +1123,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -655,7 +655,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -905,7 +905,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }

View File

@ -676,7 +676,9 @@ namespace Godot
/// <returns>A string representation of this vector.</returns> /// <returns>A string representation of this vector.</returns>
public readonly string ToString(string? format) public readonly string ToString(string? format)
{ {
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}), {W.ToString(format)})"; #pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider"
return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})";
#pragma warning restore CA1305
} }
} }
} }