HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcsharpMinor

Adding compile-time format validation to your string.Format calls

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
callsformatyourcompilevalidationtimeaddingstring

Problem

I've written another diagnostic for VSDiagnostics that adds compile-time security for your formatting specified in a string.Format call. The exact scenario it guards against is when you have something like this:

string s = string.Format("Hello {0}, I'm {1}!", "John");


This will throw a runtime exception because it cannot find an argument for the second placeholder. What my analyzer does is evaluate the format, looks at the eligible placeholders and compares that with the amount of arguments that have been passed in. When it determines that the format is invalid for the given arguments, it will underline the format and report an error-level diagnostic.

Note that the purpose of this analyzer should be the above scenario. Other things like placeholders being in a non-lexical order or unused placeholders are handled separately.

There are a few restrictions in place:

  • The specified format has to be a literal -- it cannot be retrieved from a field, method call or anything else



  • Interpolated strings as a format specified are not (yet) supported



  • If the arguments are passed in using an explicit array, only inline initialized arrays are accepted. Arrays defined elsewhere are not supported.



I am mostly interested in finding a way to make the logic of selecting the format a little more cleanly. Additionally (perhaps more importantly): can you find a scenario that I haven't accounted for? All verified scenarios so far can be found here.

Analyzer Github

```
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class StringDotFormatWithDifferentAmountOfArgumentsAnalyzer : DiagnosticAnalyzer
{
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
private static readonly string Category = VSDiagnosticsResources.StringsCategory;
private static readonly string Message = VSDiagnosticsResources.StringDotFormatWithDifferentAmountOfArgumentsMessage;
private static readonly string Title = VSDiagnosticsResources.StringDotFormatWithDiffe

Solution

-
Instead of looking for a string literal expression, call SemanticModel.GetConstantValue() on the argument node.

This will work properly with string concatenation or constant fields.

-
Instead of hard-coding String.Format and looking at argument types, look for all invocations whose parameter lists end with string format followed by one or more object or params object[] parameters. This will let you work with other formatting methods like TextWriter.WriteLine

-
IsAnInvocationOf should not assume MemberAccess (eg, using static); instead, get the symbol for the invocation expression itself.

Context

StackExchange Code Review Q#115051, answer score: 6

Revisions (0)

No revisions yet.