Diagnostics SARIF structurés

Le compilateur MSVC peut être effectué pour générer des diagnostics en tant que SARIF (format d’échange des résultats d’analyse statique). SARIF est un format JSON lisible par l’ordinateur.

Il existe deux façons de faire en sorte que le compilateur MSVC produise des diagnostics SARIF :

  • Passez le /experimental:log commutateur sur la ligne de commande. Pour plus d’informations, consultez la documentation /experimental:log .
  • Lancez cl.exe programmatiquement et définissez la SARIF_OUTPUT_PIPE variable d’environnement pour récupérer des blocs SARIF via un canal.

Récupération de SARIF via un canal

Les outils qui consomment SARIF à partir du compilateur MSVC pendant qu’une compilation est en cours utilisent un canal. Consultez la documentation pour CreatePipe plus d’informations sur la création de canaux Windows.

Pour récupérer SARIF via un canal, définissez la SARIF_OUTPUT_PIPE variable d’environnement sur la représentation entière encodée UTF-16 du HANDLE canal à la fin d’écriture du canal, puis lancez cl.exe. SARIF est envoyé le long du canal comme suit :

  • Lorsqu’un nouveau diagnostic est disponible, il est écrit dans ce canal.
  • Les diagnostics sont écrits dans le canal un-à-temps plutôt qu’en tant qu’objet SARIF entier.
  • Chaque diagnostic est représenté par un message JSON-RPC 2.0 de type Notification.
  • Le message JSON-RPC est précédé d’un Content-Length en-tête avec le formulaire Content-Length: <N> suivi de deux nouvelles lignes, où <N> est la longueur du message JSON-RPC suivant en octets.
  • Le message JSON-RPC et l’en-tête sont tous deux encodés dans UTF-8.
  • Ce format JSON-RPC-with-header est compatible avec vs-streamjsonrpc.
  • Le nom de la méthode pour l’appel JSON-RPC est OnSarifResult.
  • L’appel a un paramètre unique qui est encodé par nom avec le nom resultdu paramètre .
  • La valeur de l’argument est un objet unique result tel que spécifié par la norme SARIF Version 2.1.

Exemple

Voici un exemple de résultat SARIF JSON-RPC produit par 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}}}]}}}

Données de résultat SARIF

Le compilateur génère SARIF qui peut inclure des informations supplémentaires pour représenter la structure imbriquée de certains diagnostics. Un diagnostic (représenté par un result objet SARIF) peut contenir une « arborescence de diagnostic » d’informations supplémentaires dans son relatedLocations champ. Cette arborescence est encodée à l’aide d’un conteneur de propriétés SARIF comme suit :

Le champ d’un locationproperties objet peut contenir une nestingLevel propriété dont la valeur correspond à la profondeur de cet emplacement dans l’arborescence de diagnostic. Si un emplacement n’a pas d’emplacement nestingLevel spécifié, la profondeur est considérée 0 comme étant un enfant du diagnostic racine représenté par l’objet contenant celui-ci result . Sinon, si la valeur est supérieure à la profondeur de l’emplacement qui précède immédiatement cet emplacement dans le relatedLocations champ, cet emplacement est un enfant de cet emplacement. Sinon, cet emplacement est un frère du plus proche précédent location dans le relatedLocations champ avec la même profondeur.

Exemple

Prenez le code suivant :

struct dog {};
struct cat {};

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

struct lizard {};

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

Lorsque ce code est compilé, le compilateur produit l’objet suivant result (physicalLocation les propriétés ont été supprimées pour la concision) :

{
    "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’arborescence de diagnostics logiques produite à partir des messages de cet result objet est la suivante :

  • 'pet' : aucune fonction surchargée ne peut convertir tous les types d’arguments
    • pourrait être 'void pet(cat)'
      • 'void pet(cat)' : impossible de convertir l’argument 1 de 'lézard' en 'cat'
        • Aucun opérateur de conversion défini par l’utilisateur disponible qui peut effectuer cette conversion, ou l’opérateur ne peut pas être appelé
    • ou 'void pet(dog)'
      • 'void pet(dog)' : impossible de convertir l’argument 1 de 'lézard' en 'dog'
        • Aucun opérateur de conversion défini par l’utilisateur disponible qui peut effectuer cette conversion, ou l’opérateur ne peut pas être appelé
    • lors de la tentative de correspondance avec la liste d’arguments '(lézard)'

Voir aussi

/experimental:log (Activer les diagnostics SARIF structurés)