Strukturierte SARIF-Diagnose

Der MSVC-Compiler kann zur Ausgabediagnose als SARIF (Static Analysis Results Interchange Format) erfolgen. SARIF ist ein maschinenlesbares JSON-basiertes Format.

Es gibt zwei Möglichkeiten, den MSVC-Compiler zur Erstellung von SARIF-Diagnosen zu machen:

  • Übergeben Sie den /experimental:log Schalter an die Befehlszeile. Ausführliche Informationen finden Sie in der Dokumentation /experimental:log .
  • Starten Sie programmgesteuert, und legen Sie cl.exe die SARIF_OUTPUT_PIPE Umgebungsvariable fest, um SARIF-Blöcke über eine Pipe abzurufen.

Abrufen von SARIF über ein Rohr

Tools, die SARIF vom MSVC-Compiler verbrauchen, während eine Kompilierung in Bearbeitung ist, verwenden eine Pipe. Ausführliche Informationen zum Erstellen von Windows-Rohren finden Sie in der Dokumentation CreatePipe .

Um SARIF über eine Pipe abzurufen, legen Sie die Umgebungsvariable SARIF_OUTPUT_PIPE auf die UTF-16-codierte ganzzahlige Darstellung des HANDLE Schreibendes der Pipe fest, und starten Sie cl.exedann . SARIF wird wie folgt entlang des Rohrs gesendet:

  • Wenn eine neue Diagnose verfügbar ist, wird sie in diese Pipe geschrieben.
  • Die Diagnose wird nicht als gesamtes SARIF-Objekt, sondern einzeln in die Rohrleitung geschrieben.
  • Jede Diagnose wird durch eine JSON-RPC 2.0-Nachricht vom Typ Benachrichtigung dargestellt.
  • Der JSON-RPC-Nachricht wird eine Content-Length Kopfzeile mit dem Formular Content-Length: <N> vorangestellt, gefolgt von zwei Newlines, wobei <N> die Länge der folgenden JSON-RPC-Nachricht in Byte angegeben ist.
  • Die JSON-RPC-Nachricht und der Header werden in UTF-8 codiert.
  • Dieses JSON-RPC-with-header-Format ist mit vs-streamjsonrpc kompatibel.
  • Der Methodenname für den JSON-RPC-Aufruf lautet OnSarifResult.
  • Der Aufruf verfügt über einen einzelnen Parameter, der anhand des Namens des Parameters resultcodiert wird.
  • Der Wert des Arguments ist ein einzelnes result Objekt, das durch den SARIF Version 2.1-Standard angegeben wird.

Beispiel

Hier ist ein Beispiel für ein JSON-RPC SARIF-Ergebnis, das von cl.exe:

Content-Length: 334

{"jsonrpc":"2.0","method":"OnSarifResult","params":{"result":{"ruleId":"C1034","level":"fatal","message":{"text":"iostream: no include path set"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///C:/Users/sybrand/source/repos/cppcon-diag/cppcon-diag/cppcon-diag.cpp"},"region":{"startLine":1,"startColumn":10}}}]}}}{"jsonrpc":"2.0","method":"OnSarifResult","params":{"result":{"ruleId":"C1034","level":"fatal","message":{"text":"iostream: no include path set"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///C:/Users/sybrand/source/repos/cppcon-diag/cppcon-diag/cppcon-diag.cpp"},"region":{"startLine":1,"startColumn":10}}}]}}}

SARIF-Ergebnisdaten

Der Compiler gibt SARIF aus, die zusätzliche Informationen enthalten können, um die geschachtelte Struktur einiger Diagnosen darzustellen. Eine Diagnose (dargestellt durch ein result SARIF-Objekt) kann eine "Diagnosestruktur" mit zusätzlichen Informationen in seinem relatedLocations Feld enthalten. Diese Struktur wird mit einem SARIF-Eigenschaftenbehälter wie folgt codiert:

Das Feld eines location Objekts properties kann eine nestingLevel Eigenschaft enthalten, deren Wert die Tiefe dieser Position in der Diagnosestruktur ist. Wenn ein Speicherort nicht über einen nestingLevel angegebenen Wert verfügt, wird als Tiefe betrachtet 0 , und dieser Speicherort ist ein untergeordnetes Element der Stammdiagnose, die durch das Objekt dargestellt wird, das result es enthält. Andernfalls ist der Wert größer als die Tiefe der Position, die relatedLocations unmittelbar vor dieser Position im Feld liegt, ein untergeordnetes Element dieser Position. Andernfalls ist diese Position ein gleichgeordnetes Element des am nächsten vorangehenden location relatedLocations Felds mit derselben Tiefe.

Beispiel

Betrachten Sie folgenden Code:

struct dog {};
struct cat {};

void pet(dog);
void pet(cat);

struct lizard {};

int main() {
    pet(lizard{});
}

Wenn dieser Code kompiliert wird, erzeugt der Compiler das folgende result Objekt (physicalLocation Eigenschaften wurden aus Platzgründen entfernt):

{
    "ruleId": "C2665",
    "level": "error",
    "message": {
        "text": "'pet': no overloaded function could convert all the argument types"
    },
    "relatedLocations": [
        {
            "id": 0,
            "message": {
                "text": "could be 'void pet(cat)'"
            }
        },
        {
            "id": 1,
            "message": {
                "text": "'void pet(cat)': cannot convert argument 1 from 'lizard' to 'cat'"
            },
            "properties": {
                "nestingLevel": 1
            }
        },
        {
            "id": 2,
            "message": {
                "text": "No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called"
            },
            "properties": {
                "nestingLevel": 2
            }
        },
        {
            "id": 3,
            "message": {
                "text": "or       'void pet(dog)'"
            }
        },
        {
            "id": 4,
            "message": {
                "text": "'void pet(dog)': cannot convert argument 1 from 'lizard' to 'dog'"
            },
            "properties": {
                "nestingLevel": 1
            }
        },
        {
            "id": 5,
            "message": {
                "text": "No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called"
            },
            "properties": {
                "nestingLevel": 2
            }
        },
        {
            "id": 6,
            "message": {
                "text": "while trying to match the argument list '(lizard)'"
            }
        }
    ]
}

Die logische Diagnosestruktur, die aus den Nachrichten in diesem result Objekt erzeugt wird, lautet:

  • "Pet": Keine überladene Funktion konnte alle Argumenttypen konvertieren.
    • könnte "void pet(cat)" sein
      • "void pet(cat)": Argument 1 kann nicht von "Lizard" in "Katze" konvertiert werden.
        • Kein benutzerdefinierter Konvertierungsoperator verfügbar, der diese Konvertierung ausführen kann, oder der Operator kann nicht aufgerufen werden.
    • oder "void pet(dog)"
      • "void pet(dog)": Argument 1 kann nicht von "Lizard" in "Hund" umgewandelt werden.
        • Kein benutzerdefinierter Konvertierungsoperator verfügbar, der diese Konvertierung ausführen kann, oder der Operator kann nicht aufgerufen werden.
    • beim Versuch, der Argumentliste "(Lizard)" zuzuordnen

Siehe auch

/experimental:log (Aktivieren der strukturierten SARIF-Diagnose)