Wie kann ich meine Codediagnosesyntaxknotenaktion für geschlossene Dateien ausführen lassen?

73

Ich erstelle eine Reihe von Codediagnosen mit Roslyn (in der VS2015-Vorschau). Im Idealfall möchte ich, dass alle Fehler, die sie erzeugen, als dauerhafte Fehler wirken, als würde ich gegen eine normale Sprachregel verstoßen.

Es gibt eine Reihe von Optionen, aber es fällt mir schwer, eine davon konsequent zum Laufen zu bringen. Ich habe es geschafft, eine rudimentäre Syntaxknotenaktion zu implementieren, dh eine, bei der registriert ist

context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);

in der InitializeMethode meiner diagnostischen Klasse. Siehe da, wenn ich eine Datei öffne, die gegen diese Diagnose verstößt (während das VSIX-Projekt ausgeführt wird), zeigt VS2015 einen Fehler an:

  • Rotes Kringel unter dem rechten Code
  • Roter Block am Rand
  • Fehler in der Fehlerliste

Der Fehler verschwindet jedoch, wenn ich die Datei schließe.

Ich habe es auch versucht context.RegisterCompilationEndAction, aber das hat zwei Probleme:

  • Es scheint uneinheitlich zu feuern. Wenn ich die Lösung öffne, wird sie normalerweise ausgelöst, aber nicht immer. Es wird nicht bei einem Clean / Rebuild ausgelöst, was seltsam erscheint.
  • Obwohl die direkt in der Analysemethode erstellte Diagnose ausgelöst wird, verwende ich zur Implementierung der Diagnose einen Besucher wie diesen - was möglicherweise unpassend ist:

    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);
            }
        }
    }
    

    Ich weiß, dass die Diagnose erstellt wird - ein Haltepunkt in der ReportDiagnosticZeile wird mehrmals getroffen -, aber ich sehe nichts in der Fehlerliste. (Während eines ähnlichen ReportDiagnosticAnrufs zu Beginn des Verfahrens oder eines pro Syntaxbaum mit der Pfaddatei, nicht gezeigt bekommen.)

Was mache ich hier falsch? Der erste Ansatz (eine Syntaxknotenaktion) wäre ideal, wenn er machbar wäre - er gibt mir genau den Kontext, den ich brauche. Gibt es in den Projekteigenschaften einige Einstellungen, die der Compiler für die Kompilierung des "vollständigen Projekts" sowie für die interaktive Verarbeitung "in der IDE" verwenden muss? Ist das vielleicht nur ein bisschen Roslyn-Integration, die noch nicht ganz fertig ist?

(Ich kann den vollständigen Code für die Klasse einfügen, wenn dies nützlich wäre. In diesem Fall vermute ich jedoch, dass es mehr Rauschen als Signal ist.)

Jon Skeet
quelle
1
Nach dem, was ich bei einem Vortrag verstanden habe, RegisterCompilationEndActionist es in der Tat das, was Sie brauchen, und die Tatsache, dass es uneinheitlich ausgelöst wird, ist ein Fehler. Ich werde dem Sprecher eine E-Mail senden und fragen.
Benjamin Gruenbaum

Antworten:

46

Bei Problemen mit geschlossenen Dateien ist es unsere Absicht, dass alle Diagnosen entweder aus offenen oder geschlossenen Dateien gemeldet werden. In der Vorschau unter Extras \ Optionen \ Texteditor \ C # \ Erweitert gibt es eine Benutzeroption, mit der Sie die Diagnose in geschlossene Dateien aufnehmen können. Wir hoffen, dies als Standard festzulegen, bevor VS 2015 veröffentlicht wird. Beachten Sie jedoch, dass die Option nur für Analysen innerhalb von VS gilt. Wenn Ihr Analysator an den Compiler übergeben wird (indem Sie einen Analysator im Projektmappen-Explorer hinzufügen oder einen NuGet-Paketverweis auf ein Paket mit einem Analysator hinzufügen, anstatt VSIX in Visual Studio zu installieren), meldet der Compiler alle Diagnosen, wenn der Benutzer erstellt, unabhängig davon, ob die Dateien geöffnet sind oder nicht.

Für das zweite Problem mit RegisterCompilationEndedAnalyzerwird es in Visual Studio in der VS 2015-Vorschau nicht zuverlässig aufgerufen. Dies liegt daran, dass wir einige Optimierungen vornehmen, um zu vermeiden, dass alles erneut auf "lokale" Änderungen in Methodenkörpern analysiert wird. Aus ähnlichen Gründen melden wir derzeit keine Fehler, die mit Positionen in Methodenkörpern gemeldet werden. Wir haben dies erst kürzlich geändert, sodass VS nach einer längeren Verzögerung eine vollständige Neuanalyse startet und daher RegisterCompilationEndedAnalyzerin zukünftigen Builds zuverlässig aufgerufen werden sollte, und wir werden Fehler unabhängig vom Standort melden.

Für Ihren Fall ist es jedoch richtig, bei einem SyntaxNodeAnalyzer zu bleiben, die VS-Option zu wechseln, um die Diagnose in geschlossenen Dateien zu aktivieren, und Ihre Diagnose an die Projektkompilierungsoptionen anzuhängen.

Hoffe das hilft!

Kevin Pilch
quelle
2
Aha - der Ortsteil würde definitiv die Kuriositäten erklären, die ich sah. Meine Diagnose "Nur überprüfen, ob ich etwas zum Laufen bringen kann" hatte keinen Speicherort, daher wurden diese angezeigt ... und die Option für die Diagnose in geschlossenen Dateien funktionierte einwandfrei. Vielen Dank! Zurück zu der Diagnose selbst, die jetzt das Richtige tut :)
Jon Skeet
Haben Sie den Hinweis zur Verwendung der im Projekt angehängten Diagnose gesehen, um sie auch in die Befehlszeilenerstellung zu integrieren?
Kevin Pilch
Ja. Solange ich auf dem richtigen Weg bin, um das später zu tun, kann ich vorerst darauf punt :)
Jon Skeet
1
@ KevinPilch Dies scheint immer noch standardmäßig für VS2017.4 deaktiviert zu sein und war für mich sehr überraschend. Irgendein Wort darüber, ob dies geändert wird?
JamesFaix