Skip to content

Fix MA0075 false positive on Enum.ToString and handle conditional access - #1311

Merged
meziantou merged 1 commit into
mainfrom
fix-ma0075-enum-tostring
Aug 20, 2026
Merged

Fix MA0075 false positive on Enum.ToString and handle conditional access#1311
meziantou merged 1 commit into
mainfrom
fix-ma0075-enum-tostring

Conversation

@meziantou

Copy link
Copy Markdown
Owner

Fixes #1310

MA0075 vs MA0185 on enums

MA0075 reported Do not use implicit culture-sensitive ToString for "abc" + enumValue.ToString("G"), while MA0185 considered the very same value culture invariant.

The ToString overloads of an enum are declared on System.Enum, so invocation.TargetMethod.ContainingType is System.Enum. That type is a class, so IsEnum() returns false, and it implements IFormattable, so it was classified as culture sensitive. System.Enum ignores the format provider, so it is now part of the known culture-insensitive types.

Adding System.Enum to the type-level check rather than using invocation.Instance?.Type also covers values statically typed as System.Enum and type parameters constrained to where T : struct, Enum.

Note that the underlying gap is not new: it only became visible in #1273, which changed the string concatenation rule from analyzing only operands implicitly converted to object to analyzing every operand. Before that, a string-typed operand such as enumValue.ToString("G") was never analyzed at all.

Conditional access

Found while investigating the above: IConditionalAccessOperation was not handled, so it fell through to the generic branch that uses the type of the whole expression. For "abc" + dateTime?.ToString("F") that type is string, so the rule never reported it. The culture sensitivity is now computed from WhenNotNull.

This only affects MA0075/MA0076. MA0185 reaches interpolation holes through IInterpolatedStringAppendOperation, which works off argument types, so its behavior is unchanged.

Tests

  • Enums: concat with every format (G g F f D d X x, default(string), a non-constant string format), plain ToString(), implicit concat, nullable enums, System.Enum-typed values, user-defined enums, where T : struct, Enum, and the interpolated-string forms.
  • Conditional access: value?.ToString(), value?.ToString("F"), value?.ToString(format), value?.Date.ToString("F"), value?.Ticks.ToString(), nested value?.Child?.Value.ToString("F"), value?.Value, and the interpolated form are reported; value?.ToString("o"), value?.ToString(CultureInfo.InvariantCulture), value?.Ticks.ToString("X") and value?.Kind.ToString("G") are not.
  • MA0185 enum tests, so the two rules cannot drift apart again without a test failing.

"abc" + value?.Ticks.ToString() is reported on purpose: Ticks is a non-constant long, and MA0075 already treats non-constant signed integers as culture sensitive because of the negative sign.

Note for the reviewer

Enum.ToString("D") on an undefined value of a signed enum formats the underlying integer with the current culture, so a negative value picks up the culture's negative sign. Treating System.Enum as unconditionally invariant ignores that. This is consistent with what MA0075 already did for "abc" + enumValue and with MA0185, but it is not literally always invariant.

Validation

  • dotnet test --max-parallel-test-modules 2: 18327 passed, 0 failed (all five Roslyn versions)
  • dotnet run --project src/DocumentationGenerator: exit code 0, no generated markdown change

MA0075 reported "Do not use implicit culture-sensitive ToString" for
`"abc" + enumValue.ToString("G")` while MA0185 considered the same value
culture invariant (#1310).

The `ToString` overloads of an enum are declared on `System.Enum`, so the
containing type of the invocation is `System.Enum`, which is a class and
not an enum. It implements `IFormattable`, so it was considered culture
sensitive. `System.Enum` ignores the format provider, so it is now part
of the known culture-insensitive types. This also covers values typed as
`System.Enum` and type parameters constrained to `struct, Enum`.

The false positive only became visible in #1273: before it, the string
concatenation rule only analyzed operands that were implicitly converted
to `object`, so a `string`-typed operand was never analyzed.

`IConditionalAccessOperation` was not handled, so `"abc" +
dateTime?.ToString("F")` was evaluated using the type of the whole
expression (`string`) and never reported. It is now evaluated using the
accessed value.
@meziantou
meziantou merged commit cc58203 into main Aug 20, 2026
12 checks passed
@meziantou
meziantou deleted the fix-ma0075-enum-tostring branch August 20, 2026 17:54
This was referenced Aug 20, 2026
This was referenced Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MA0075 and MA0185 are fighting

1 participant