How can I make my code diagnostic syntax node action work on closed files?

C#Visual Studio-2015RoslynAnalyzerDiagnostics

C# Problem Overview


I'm building a set of code diagnostics using Roslyn (in VS2015 Preview). Ideally, I'd like any errors they produce to act as persistent errors, just as if I were violating a normal language rule.

There are a bunch of options, but I'm having a hard time getting any of them to work consistently. I've managed to implement a rudimentary syntax node action, i.e. one registered with

context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);

in the Initialize method of my diagnostic class. Lo and behold, when I open up a file which violates this diagnostic (while running the VSIX project), VS2015 shows an error:

  • Red squiggle under the right bit of code
  • Red block in the margin
  • Error in the error list

However, the error goes away when I close the file.

I've tried using context.RegisterCompilationEndAction as well, but this has two problems:

  • It seems to fire inconsistently. Usually when I open the solution it fires, but not always. It doesn't fire on a clean/rebuild, which seems odd.

  • Although diagnostics created directly in the analysis method fire, in order to implement the diagnostics I'm using a visitor, like this - which may be inept:

      private static void AnalyzeEndCompilation(CompilationEndAnalysisContext context)
      {
          foreach (var tree in context.Compilation.SyntaxTrees)
          {
              var visitor = new ReportingVisitor(context.Compilation.GetSemanticModel(tree));
              visitor.Visit(tree.GetRoot());
              foreach (var diagnostic in visitor.Diagnostics)
              {
                  context.ReportDiagnostic(diagnostic);
              }
          }
      }
    

I know that the diagnostics are being created - a breakpoint on the ReportDiagnostic line is hit several times - but I'm not seeing anything in the error list. (Whereas a similar ReportDiagnostic call at the start of the method, or one per syntax tree with the file path, does get shown.)

What am I doing wrong here? The first approach (a syntax node action) would be ideal if feasible - it gives me exactly the context I need. Is there some setting in the project properties that I need to make the compiler use that for "full project" compilation as well as just interactive "in the IDE" handling? Is this perhaps just a bit of Roslyn integration which isn't quite finished yet?

(I can include the full code for the class if it would be useful - in this case I suspect it would be more noise than signal though.)

C# Solutions


Solution 1 - C#

For the closed file issues, it's our intent that all diagnostics will be reported, from either open or closed files. There is a user option for it in the preview at Tools\Options\Text Editor\C#\Advanced that you can toggle to include diagnostics in closed files. We hope to make this the default before VS 2015 is released. However, note that the option only applies to analysis within VS. If your analyzer is passed to the compiler (by adding an analyzer in Solution Explorer, or adding a NuGet package reference to a package with an analyzer, as opposed to installing a VSIX into Visual Studio), then the compiler will report all diagnostics when the user builds, regardless of whether the files are open or not.

For the second issue with RegisterCompilationEndedAnalyzer, it isn't reliably called inside Visual Studio in the VS 2015 Preview. This is because we do some optimizations to avoid re-analyzing everything for "local" changes inside method bodies. For similar reasons, we currently don't report errors that are reported with locations in method bodies. We've just recently changed that so that VS will kick off a full re-analysis after a longer delay and so RegisterCompilationEndedAnalyzer should be called reliably in future builds, and we will report errors regardless of location.

However, for your case the correct thing to do is stay with a SyntaxNodeAnalyzer, switch the VS option to enable diagnostics in closed files, and attach your diagnostic to the project compilation options.

Hope this helps!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon SkeetView Question on Stackoverflow
Solution 1 - C#Kevin PilchView Answer on Stackoverflow