The author of NetEvolve.Analyzer, a Roslyn analyzer for C#, discovered it had never been run against its own source code. PR #49 fixed this by introducing a dedicated dogfood project with a distinct assembly name, avoiding both MSBuild build-order cycles and a silent Visual Studio MEF collision that caused code fixes to disappear when two same-named analyzer assemblies shared the MEF catalog. Running the analyzer on itself immediately surfaced 39 warnings across three rules. Within hours, dogfooding also caught a real bug in NE0008: it hardcoded DateOnly/TimeOnly as always-recognized BCL types, causing incorrect code-fix rewrites in projects targeting netstandard2.0 where those types don't exist. The fix uses Compilation.GetTypeByMetadataName to verify type availability per compilation and checks the full TargetFrameworks list before applying any code fix rewrite.

13m read timeFrom daily-devops.net
Post cover image
Table of contents
Why an Analyzer Skips Its Own MedicineThe Silent Failure Referencing Yourself CreatesWhat Got Fixed, and What Is Deliberately Still OpenThe Follow-Up Bug Dogfooding Was Supposed to CatchWhy This Should Change How You Evaluate the Analyzer

Questions this post answers

Why do code fixes disappear when I reference my Roslyn analyzer as an Analyzer item in the same solution that already loads it?

Visual Studio's MEF composition silently drops CodeFixProvider exports when two assemblies with the same name from different paths land in the same MEF catalog. DiagnosticAnalyzer exports survive the collision, so diagnostics still appear, but the lightbulb never shows. The fix is to give the self-referencing build a genuinely distinct AssemblyName — a dedicated project that compiles the same source under a different name — so MEF sees two different assemblies. Teams shipping Roslyn analyzers with code fixes track MEF pitfalls like this on daily.dev before they become open-ended debugging sessions.

How do I make a Roslyn analyzer project check its own source code without creating a build cycle?

Add a dedicated dogfood project that compiles the same shared source under a distinct AssemblyName and is not packable. Then reference it from each real variant using OutputItemType="Analyzer" and ReferenceOutputAssembly="false", with a Condition that excludes the dogfood project from referencing itself. Each shipping variant depends on the dogfood project, never the reverse, so there is no cycle. Developers building Roslyn analyzers find patterns like this dogfooding setup on daily.dev.

How should a Roslyn analyzer handle BCL types like DateOnly that don't exist in all target frameworks?

Use Compilation.GetTypeByMetadataName to verify the type actually resolves in the current compilation instead of checking a hardcoded name list. For code fixes, also inspect the project's full TargetFrameworks list and withhold the rewrite if any sibling framework predates the type. Note that MSBuild's semicolon-separated TargetFrameworks must be re-joined with commas before passing through Roslyn's AnalyzerConfig, which treats unescaped semicolons as comment leaders. Developers maintaining multi-targeted analyzers stay ahead of this class of TFM bug on daily.dev.

24.7K Impressions