Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[build] enable CA1305 for most projects #7993

Merged
merged 7 commits into from
May 17, 2023
Merged

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Apr 27, 2023

Context: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305
Context: https://learn.microsoft.com/dotnet/csharp/tutorials/string-interpolation#how-to-create-a-culture-specific-result-string-with-string-interpolation

In b1079a0, we found a real bug where omitting CultureInfo.InvariantCulture caused a problem under certain locales.

Let's take this a step further by making CA1305 a build error. In every case I found, it seemed that invariant culture was fine -- and some might be bugs?

This also catches cases like this that use the current culture:

$"My integer: {x}"

Where we should do this instead:

FormattableString.Invariant($"My integer: {x}")

Only a single instance for displaying a localized string/error message from MSBuild seemed like it needed the current culture:

string.Format (CultureInfo.CurrentCulture, Resources.XA2000, assembly));

And this one might not even matter, really?

Some projects that are not shipped I didn't enable yet, to keep this change smaller:

  • Projects in build-tools

  • MSBuild test projects

@jonathanpeppers
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jonathanpeppers jonathanpeppers marked this pull request as ready for review April 27, 2023 21:59
Context: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305
Context: https://learn.microsoft.com/dotnet/csharp/tutorials/string-interpolation#how-to-create-a-culture-specific-result-string-with-string-interpolation

In b1079a0, we found a real bug where omitting
`CultureInfo.InvariantCulture` caused a problem under certain locales.

Let's take this a step further by making `CA1305` a build error. In
every case I found, it seemed that invariant culture was fine -- and
some might be bugs?

This also catches cases like this that use the current culture:

    $"My integer: {x}"

Where we should do this instead:

    FormattableString.Invariant($"My integer: {x}")

Only a single instance for displaying a localized string/error message
from MSBuild seemed like it needed the current culture:

    string.Format (CultureInfo.CurrentCulture, Resources.XA2000, assembly));

And this one might not even matter, really?

Some projects that are not shipped I didn't enable yet, to keep this
change smaller:

* Projects in `build-tools`

* MSBuild test projects
@jpobst
Copy link
Contributor

jpobst commented Apr 29, 2023

It might be simpler to add a new /src/.editorconfig that changes only this rule. It will override the root .editorconfig for just this setting and will only apply to /src, so we don't need to add the <NoWarn> in all the other project files.

https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2022#file-hierarchy-and-precedence

@jonathanpeppers
Copy link
Member Author

It might be simpler to add a new /src/.editorconfig that changes only this rule. It will override the root .editorconfig for just this setting and will only apply to /src, so we don't need to add the <NoWarn> in all the other project files.

https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2022#file-hierarchy-and-precedence

I made this change, and the diff is a lot smaller now. Only projects in src get the rule now.

@@ -530,7 +531,7 @@ public void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan<
}

if (minfo == null)
throw new InvalidOperationException (String.Format ("Specified managed method '{0}' was not found. Signature: {1}", mname.ToString (), signature.ToString ()));
throw new InvalidOperationException (FormattableString.Invariant ($"Specified managed method '{mname.ToString ()}' was not found. Signature: {signature.ToString ()}"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should either use {mname}…{signature} or use {mname.ToString(CultureInfo.InvariantCulture)}…{signature.ToString(CultureInfo.InvariantCulture). What is here will call .ToString() with whatever is the current culture, which is most likely not the Invariant culture, and then pass the output of .ToString() on to FormattableString.Invariant().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these two you have to call ToString() because they are both ReadonlySpan<char>.

For some reason you can't string interpolate these like $"Foo: {foo}"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, "playing around" in csharp:

CultureInfo.CurrentCulture = new CultureInfo("de-DE");
double d = 42.5;
d.ToString(); // "42,5"
FormattableString.Invariant($"{d}");            // "42.5"  
FormattableString.Invariant($"{d.ToString()}"); // "42,5"

d.ToString() is "immediate", and thus uses the current culture ("de-DE", German), which is not Invariant output.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, we'd get a CA1305 build error if these were wrong. ReadonlySpan<char> doesn't have an overload for ToString():

https://learn.microsoft.com/en-us/dotnet/api/system.readonlyspan-1.tostring?view=net-8.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In such cases we should use code like this

@@ -0,0 +1,2 @@
[*.{cs,vb}]
dotnet_diagnostic.CA1305.severity = error # Specify IFormatProvider
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why enable this just in src and not repo-wide?

Copy link
Member Author

@jonathanpeppers jonathanpeppers May 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the suggestion here: #7993 (comment)

There were a lot of tests, build-tools, Mono.Options, etc. that would also need to be addressed or use $(NoWarn).

/// <summary>
/// IFormatProvider passed to any underlying string.Format() calls. Defaults to System.Globalization.CultureInfo.CurrentCulture.
/// </summary>
public static IFormatProvider FormatProvider { get; set; } = CultureInfo.CurrentCulture;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh, one last change: this should be wrapped in a #if ANDROID_34 block, as we shouldn't be updating API-33!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably just change visibility?

#if ANDROID_34
    public
#endif
    static IFormatProvider FormatProvider { get; set; } = CultureInfo.CurrentCulture;

@jonpryor
Copy link
Member

Commit message:

Context: b1079a0e02117b626dd98f8f8608be470056ce3f
Context: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305
Context: https://learn.microsoft.com/dotnet/csharp/tutorials/string-interpolation#how-to-create-a-culture-specific-result-string-with-string-interpolation

In b1079a0e, we found a real bug where omitting
`CultureInfo.InvariantCulture` caused problems under certain locales.

Let's take this a step further by making `CA1305` a build error.
In every case I found, it seemed that invariant culture was fine, and
some might be bugs?

This also catches cases like this that use the current culture:

	$"My integer: {x}"

Where we should do this instead:

	FormattableString.Invariant($"My integer: {x}")

Only a single instance for displaying a localized string/error
message from MSBuild seemed like it needed the current culture:

	string.Format (CultureInfo.CurrentCulture, Resources.XA2000, assembly);

And this one might not even matter, as `assembly` is a string.

For on-device app execution, add a new
`Android.Util.Log.FormatProvider` property, which is used by all the
log methods.  This mirrors [`TextWriter.FormatProvider`][1]:

	namespace Android.Util {
	    partial class Log {
	        public static IFormatProvider FormatProvider { get; set; } = CultureInfo.CurrentCulture;
	        public static int Debug (string tag, string format, params object[] args) =>
	            Debug (tag, string.Format (FormatProvider, format, args));
	    }
	}

Some projects that are not shipped I didn't enable yet, to keep this
change smaller:

  * Projects in `build-tools`

  * MSBuild test projects

  * Use `src/.editorconfig`; see also
    [`.editorconfig` File hierarchy and precedence][0]

Finally, `build-tools/automation/guardian/source.gdnsuppress` needed
to be updated because the existing `Log.Wtf()` methods were changed
to use the new `Log.FormatProvider` property.

[0]: https://learn.microsoft.com/visualstudio/ide/create-portable-custom-editor-options#file-hierarchy-and-precedence
[1]: https://learn.microsoft.com/en-us/dotnet/api/system.io.textwriter.formatprovider?view=net-8.0

@jonpryor jonpryor merged commit 04e4bb1 into dotnet:main May 17, 2023
@jonathanpeppers jonathanpeppers deleted the CA1305 branch May 17, 2023 15:55
grendello added a commit to grendello/xamarin-android that referenced this pull request May 18, 2023
* main:
  [build] enable CA1305 for most projects (dotnet#7993)
  Bump to xamarin/monodroid@5aed7edd (dotnet#8043)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants