Condividi tramite


Diagnostica SARIF strutturata

Il compilatore MSVC può essere eseguito per restituire la diagnostica come SARIF (Static Analysis Results Interchange Format). SARIF è un formato basato su JSON leggibile dal computer.

Esistono due modi per fare in modo che il compilatore MSVC produca diagnostica SARIF:

  • Passare l'opzione /experimental:log sulla riga di comando. Per informazioni dettagliate, vedere la documentazione /experimental:log .
  • Avviare cl.exe a livello di codice e impostare la SARIF_OUTPUT_PIPE variabile di ambiente per recuperare i blocchi SARIF attraverso una pipe.

Recupero di SARIF tramite una pipe

Gli strumenti che utilizzano SARIF dal compilatore MSVC mentre è in corso una compilazione usano una pipe. Per informazioni dettagliate sulla creazione di pipe di Windows, vedere la documentazione CreatePipe .

Per recuperare SARIF tramite una pipe, impostare la SARIF_OUTPUT_PIPE variabile di ambiente come rappresentazione integer con codifica UTF-16 dell'oggetto HANDLE alla fine di scrittura della pipe, quindi avviare cl.exe. SARIF viene inviato lungo la pipe come indicato di seguito:

  • Quando è disponibile una nuova diagnostica, viene scritta in questa pipe.
  • La diagnostica viene scritta nella pipe una alla volta anziché come intero oggetto SARIF.
  • Ogni diagnostica è rappresentata da un messaggio JSON-RPC 2.0 di tipo Notification.
  • Il messaggio JSON-RPC è preceduto da un'intestazione Content-Length con il formato Content-Length: <N> seguito da due nuove righe, dove <N> è la lunghezza del seguente messaggio JSON-RPC in byte.
  • Il messaggio e l'intestazione JSON-RPC sono entrambi codificati in UTF-8.
  • Questo formato JSON-RPC-with-header è compatibile con vs-streamjsonrpc.
  • Il nome del metodo per la chiamata JSON-RPC è OnSarifResult.
  • La chiamata ha un singolo parametro codificato in base al nome con il nome resultdel parametro .
  • Il valore dell'argomento è un singolo result oggetto specificato dallo standard SARIF Versione 2.1.

Esempio

Di seguito è riportato un esempio di risultato SARIF JSON-RPC prodotto da 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}}}]}}}

Dati dei risultati SARIF

Il compilatore restituisce SARIF che può includere informazioni aggiuntive per rappresentare la struttura annidata di alcuni dati di diagnostica. Una diagnostica (rappresentata da un result oggetto SARIF) può contenere un "albero di diagnostica" di informazioni aggiuntive nel relativo relatedLocations campo. Questo albero viene codificato usando un contenitore di proprietà SARIF come indicato di seguito:

Il campo di properties un location oggetto può contenere una nestingLevel proprietà il cui valore è la profondità di questa posizione nell'albero di diagnostica. Se una posizione non ha un nestingLevel oggetto specificato, la profondità viene considerata come 0 e questa posizione è un elemento figlio della diagnostica radice rappresentata dall'oggetto result che lo contiene. In caso contrario, se il valore è maggiore della profondità della posizione immediatamente precedente a questa posizione nel relatedLocations campo, questa posizione è un elemento figlio di tale posizione. In caso contrario, questa posizione è un elemento di pari livello del precedente più location vicino nel relatedLocations campo con la stessa profondità.

Esempio

Osservare il codice seguente:

struct dog {};
struct cat {};

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

struct lizard {};

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

Quando questo codice viene compilato, il compilatore produce l'oggetto seguente result (physicalLocation le proprietà sono state rimosse per brevità):

{
    "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)'"
            }
        }
    ]
}

L'albero di diagnostica logico prodotto dai messaggi in questo result oggetto è:

  • 'pet': nessuna funzione di overload potrebbe convertire tutti i tipi di argomento
    • potrebbe essere 'void pet(cat)'
      • 'void pet(cat)': impossibile convertire l'argomento 1 da 'lucertola' a 'cat
        • Non è disponibile alcun operatore di conversione definito dall'utente che può eseguire questa conversione oppure non è possibile chiamare l'operatore
    • o 'void pet(dog)'
      • 'void pet(dog)': impossibile convertire l'argomento 1 da 'lucertola' a 'dog'
        • Non è disponibile alcun operatore di conversione definito dall'utente che può eseguire questa conversione oppure non è possibile chiamare l'operatore
    • durante il tentativo di trovare la corrispondenza con l'elenco di argomenti '(lucertola)'

Vedi anche

/experimental:log (Abilitare la diagnostica SARIF strutturata)