Last time we talked about the basics of creating an analyzer. Now that we have some working code, let's tweak it a bit. We're going start by fixing a small issue with the default code to update it to handle partial classes.

Let's look for a minute at how our current analyzer handles partial classes. I created a file with the partial class Foo declared multiple times. As you see, it only reports the diagnostic on one of the two declared instances.

PartialClass

Looking into the analyzer code, its pretty easy to see why. If you look at the AnalyzeSymbol method, when the diagnostic is created, it uses the first location to report the diagnostic.

private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
    // TODO: Replace the following code with your own analysis, generating Diagnostic objects for any issues you find
    var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;

    // Find just those named type symbols with names containing lowercase letters.
    if (namedTypeSymbol.Name.ToCharArray().Any(char.IsLower))
    {
        // For all such symbols, produce a diagnostic.
        var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);

        context.ReportDiagnostic(diagnostic);
    }
}

Since Locations is an ImmutableArray of Location, we can simply iterate over that and report all of the diagnostics for this symbol.

private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
    // TODO: Replace the following code with your own analysis, generating Diagnostic objects for any issues you find
    var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;

    // Find just those named type symbols with names containing lowercase letters.
    if (namedTypeSymbol.Name.ToCharArray().Any(char.IsLower))
    {
        foreach (var location in namedTypeSymbol.Locations)
        {
            // For all such symbols, produce a diagnostic.
            var diagnostic = Diagnostic.Create(Rule, location, namedTypeSymbol.Name);

            context.ReportDiagnostic(diagnostic);
        }
    }
}

Running the analyzer project again, you will now see that the diagnostic is reported on both of the declarations of the partial class.

PartialClassFixed

The important lesson to take away here is that there are a lot of ways to do things in C# and when writing an analyzer you need to consider that. Partials are a crucial part of the framework and failing to account for them in your analyzer will leave a small, but sometimes annoying, hole in your analyzers coverage.