Skip to content

dayforce-hcm/Utf8StringInterpolation.Analyzers

Repository files navigation

Utf8StringInterpolation.Analyzers

NuGet License: MIT

Roslyn analyzers for Utf8StringInterpolation — the zero-allocation UTF-8 string interpolation library by Cysharp. These analyzers catch usage patterns that silently defeat the library's performance guarantees at compile time, turning invisible runtime regressions into build errors.

The problem

Utf8StringInterpolation achieves zero allocation by making Utf8StringWriter<T> an interpolated string handler. When you call AppendFormat($"..."), the C# compiler routes the interpolation directly into the handler — no intermediate string is ever created.

However, Utf8StringWriter<T> also exposes Append(string?). When you write Append($"..."), the compiler sees a plain string parameter with no handler attribute, so it materializes the entire interpolated string as a heap-allocated string first, then passes it in. The code compiles cleanly, produces correct output, and silently allocates — the exact opposite of the library's purpose.

// Looks identical. Behaves very differently.
zsb.Append($"Hello, {name}!");       // allocates a string — WRONG
zsb.AppendFormat($"Hello, {name}!"); // zero allocation — correct

This package makes the wrong form a build error.

Diagnostics

U8SI001 — Use AppendFormat instead of Append with interpolated strings

Severity: Error
Category: Performance

Before (build error):

using Utf8StringInterpolation;

var zsb = Utf8String.CreateWriter(stream);
zsb.Append($"Hello, {name}!");         // error U8SI001
zsb.Append($"You have {count} items."); // error U8SI001

After (zero allocation):

zsb.AppendFormat($"Hello, {name}!");
zsb.AppendFormat($"You have {count} items.");

A code fix is provided. In Visual Studio, click the lightbulb on any U8SI001 error to replace Append with AppendFormat automatically. On the command line:

dotnet format analyzers <project> --diagnostics U8SI001 --severity error

Append($"literal") with no interpolation holes is intentionally ignored. If the interpolated string contains no {...} placeholders, the compiler resolves it to a string constant at compile time — there is no heap allocation at runtime. The diagnostic only fires when actual interpolation holes are present, because those are the cases where AppendFormat provides a performance benefit.

Installation

<PackageReference Include="Utf8StringInterpolation.Analyzers" Version="x.y.z">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

The package contains both the analyzer and the code fix provider. It has no runtime impact — PrivateAssets="all" ensures it is not listed as a dependency of your package.

Heads up for existing codebases: Adding this package to a project that already has Append($"...") calls produces immediate build errors. Run dotnet format analyzers --diagnostics U8SI001 --severity error on the project to fix existing violations before (or immediately after) adding the PackageReference.

Compatibility

  • C# projects targeting any .NET version (.NET Framework, .NET Core, .NET 5+)
  • Requires the Utf8StringInterpolation NuGet package
  • Tested with Visual Studio, VS Code, and dotnet build

How it works

The analyzer registers on every InvocationExpression and checks:

  1. The method name is Append
  2. At least one argument is an InterpolatedStringExpressionSyntax containing at least one interpolation hole ({...})
  3. The receiver type is Utf8StringInterpolation.Utf8StringWriter<T> (verified via semantic model, not string matching)

Because Utf8StringWriter<T>.Append has no interpolated string handler overload, any $"..." argument with holes is necessarily materialized as a heap-allocated string by the compiler. Interpolated strings without holes are compile-time constants and are excluded — they have no performance cost.

If all three conditions hold, U8SI001 is reported on the method name. The code fix rewrites the method name to AppendFormat, leaving the argument unchanged.

Related

Contributing

Bug reports and pull requests welcome. The repository includes unit tests (Roslyn testing framework) and an integration test that builds a real .NET Framework project, applies the code fix via dotnet format, and verifies the result.

Versioning

Every push to master publishes a new patch version automatically via Nerdbank.GitVersioning. The version is major.minor.<commit-height>. To bump major or minor, edit version.json.

License

MIT

About

Roslyn analyzers for the Utf8StringInterpolation library that catch suboptimal usage patterns at compile time.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages