Frage

Ich versuche, die folgende VBA-Anweisung zu korrigieren (einigen alten Code nur zum Spaß umzuwandeln und Roslyn zu lernen, überhaupt nicht auf der Suche nach etwas Perfektem), um die zu entfernen Set Schlüsselwort, damit es eine gültige VB.NET-Anweisung ist:

Set f = New Foo()

Wenn ich es mit dem Syntax Visualizer betrachte, sehe ich, dass es sich in nachgestellte Trivialitäten verwandelt.

Syntax Visualizer

Ich versuche herauszufinden, wie ich es mithilfe einer Abfrage finden kann.Ich habe mehrere Ansätze ausprobiert, aber alle folgenden Ergebnisse blieben erfolglos:

var attempt1 = root.DescendantTokens().Where(t=>t.IsKind(SyntaxKind.SkippedTokensTrivia));
var attempt2 = root.DescendantTokens().Where(t => t.IsKind(SyntaxKind.SetKeyword));
var attempt3 = root.DescendantTrivia().Where(t => t.IsKind(SyntaxKind.SetKeyword));
var attempt4 = root.DescendantNodes()
                   .OfType<EmptyStatementSyntax>()
                   .Where(e => e.DescendantTokens().Any(t => t.IsKeyword()));

(Ja, ich verwende C#, um mit a zu arbeiten VisualBasicSyntaxTree)

Ich kann das einfach nicht finden SetKeyword Token, das im Visualizer angezeigt wird, also dachte ich, dass es vielleicht etwas mehr Arbeit kostet, herauszufinden, was es wirklich ist (ist das mit strukturierten Trivia gemeint?).Ich habe in der Dokumentation etwas gelesen, in dem erwähnt wurde, dass der Compiler die Darstellung auf verschiedene Arten wählen kann, daher dachte ich, dass dies hier möglicherweise der Fall ist.

Die Abfrage war nur das erste, was ich versucht habe, aber in Wirklichkeit habe ich eine SyntaxRewriter Ich verwende den Code, um alle derartigen Probleme zu finden und zu beheben (ich bin beispielsweise bereits in der Lage, fehlende Klammern um ArgumentLists zu beheben), aber in diesem Fall kann ich anscheinend nicht herausfinden, welche Visit-Methode überschrieben werden soll.

Also noch einmal, 1) wie man diese vom Stamm aus abfragt und 2) die beste Überschreibung, die man von einem Rewriter auswählen kann.Ich hämmere mir seit zwei Tagen mit dem Gesicht auf die Tastatur, was die Wahrscheinlichkeit exponentiell erhöht, dass ich einen Cranio-/Recto-Insertion-Moment habe und ich eine von euch guten Seelen brauche, die mich da rausholt.

Prost!Brian

Bearbeiten:Tippfehler in Abfrageversuch1 behoben

War es hilfreich?

Lösung

Es scheint also, dass der Compiler, wenn er einen Fehlerzustand erreicht, alle Token bis zum nächsten Punkt überspringt, an dem er die Analyse wiederherstellen und fortsetzen kann (in diesem Fall das Ende der Zeile).Der Knoten, der diesen Fehlerzustand darstellt, ist ein EmptyStatement mit abschließenden Syntax-Trivia, die den Rest des Textes als analysierte Token enthalten.

Wenn Sie also einen Knoten neu schreiben möchten, müssen Sie ihn neu schreiben EmptyStatements.Sie möchten jedoch nicht irgendeine leere Anweisung schreiben, sondern nur solche mit dem Diagnosecode „BC30807“.

public override SyntaxNode VisitEmptyStatement(EmptyStatementSyntax node)
{
    var diagnostic = GetLetSetDiagnostic(node);
    if (diagnostic == null)
        return base.VisitEmptyStatement(node);
    return RewriteLetSetStatement(node);
}

private Diagnostic GetLetSetDiagnostic(EmptyStatementSyntax node)
{
    //'Let' and 'Set' assignment statements are no longer supported.
    const string code = "BC30807";
    return node.GetDiagnostics().SingleOrDefault(n => n.Id == code);
}

Die Umsetzung der RewriteLetSetStatement() Die Methode ist für mich ein bisschen rätselhaft. Ich bin mir nicht sicher, wie sie mithilfe der Compiler-Dienste effektiv implementiert werden kann. Ich glaube nicht, dass dies ein Anwendungsfall ist, den sie gut abdeckt.Die Trivia behält die analysierten Token bei, aber mit diesen Token kann man AFAIK nicht viel anfangen.

Im Idealfall würden wir das einfach ignorieren wollen Set token aus den Tokens und wirf es zur erneuten Analyse zurück in den Parser.Und soweit ich weiß, ist das nicht möglich, wir können nur aus Text analysieren.

Ich schätze also, das nächstbeste wäre, den Text zu nehmen und ihn umzuschreiben, um das zu entfernen Set und analysieren Sie den Text erneut.

private SyntaxNode RewriteLetSetStatement(EmptyStatementSyntax node)
{
    var letSetTokens = node.GetTrailingTrivia()
        .Where(triv => triv.IsKind(SyntaxKind.SkippedTokensTrivia))
        .SelectMany(triv => triv.GetStructure().ChildTokens())
        .TakeWhile(tok => new[] {SyntaxKind.LetKeyword, SyntaxKind.SetKeyword}
                          .Contains(tok.VisualBasicKind()));
    var span = new RelativeTextSpan(node.FullSpan);
    var newText = node.GetText().WithChanges(
        // replacement spans must be relative to the text
        letSetTokens.Select(tok => new TextChange(span.GetSpan(tok.Span), ""))
    );
    return SyntaxFactory.ParseExecutableStatement(newText.ToString());
}

private class RelativeTextSpan(private TextSpan span)
{
    public TextSpan GetSpan(TextSpan token)
    {
        return new TextSpan(token.Start - span.Start, token.Length);
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top