Diagnósticos de SARIF estructurados

El compilador de MSVC se puede realizar para generar diagnósticos como SARIF (formato de intercambio de resultados de análisis estáticos). SARIF es un formato basado en JSON legible por la máquina.

Hay dos maneras de hacer que el compilador de MSVC genere diagnósticos SARIF:

  • Pase el /experimental:log modificador en la línea de comandos. Consulte la documentación para /experimental:log obtener más información.
  • Inicie cl.exe mediante programación y establezca la SARIF_OUTPUT_PIPE variable de entorno para recuperar bloques SARIF a través de una canalización.

Recuperación de SARIF a través de una canalización

Las herramientas que consumen SARIF del compilador de MSVC mientras una compilación está en curso usan una canalización. Consulte la documentación para obtener CreatePipe más información sobre cómo crear canalizaciones de Windows.

Para recuperar SARIF a través de una canalización, establezca la SARIF_OUTPUT_PIPE variable de entorno para que sea la representación entera codificada con UTF-16 de en HANDLE el extremo de escritura de la canalización y, a continuación, inicie cl.exe. SARIF se envía a lo largo de la tubería de la siguiente manera:

  • Cuando hay disponible un nuevo diagnóstico, se escribe en esta canalización.
  • Los diagnósticos se escriben en la canalización de uno a uno en lugar de como un objeto SARIF completo.
  • Cada diagnóstico se representa mediante un mensaje JSON-RPC 2.0 de tipo Notificación.
  • El mensaje JSON-RPC tiene como prefijo un Content-Length encabezado con el formulario Content-Length: <N> seguido de dos nuevas líneas, donde <N> es la longitud del siguiente mensaje JSON-RPC en bytes.
  • Tanto el mensaje JSON-RPC como el encabezado se codifican en UTF-8.
  • Este formato JSON-RPC-with-header es compatible con vs-streamjsonrpc.
  • El nombre del método para la llamada JSON-RPC es OnSarifResult.
  • La llamada tiene un único parámetro codificado por nombre con el nombre resultdel parámetro .
  • El valor del argumento es un único result objeto especificado por el estándar SARIF Versión 2.1.

Ejemplo

Este es un ejemplo de un resultado DE SARIF JSON-RPC generado por 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}}}]}}}

Datos de resultados de SARIF

El compilador genera SARIF que puede incluir información adicional para representar la estructura anidada de algunos diagnósticos. Un diagnóstico (representado por un result objeto SARIF) puede contener un "árbol de diagnóstico" de información adicional en su relatedLocations campo. Este árbol se codifica mediante un contenedor de propiedades SARIF de la siguiente manera:

El campo de properties un location objeto puede contener una nestingLevel propiedad cuyo valor es la profundidad de esta ubicación en el árbol de diagnóstico. Si una ubicación no tiene un nestingLevel especificado, se considera 0 que la profundidad es y esta ubicación es un elemento secundario del diagnóstico raíz representado por el result objeto que lo contiene. De lo contrario, si el valor es mayor que la profundidad de la ubicación inmediatamente anterior a esta ubicación en el relatedLocations campo, esta ubicación es un elemento secundario de esa ubicación. De lo contrario, esta ubicación es un elemento relacionado del elemento anterior más location cercano en el relatedLocations campo con la misma profundidad.

Ejemplo

Observe el código siguiente:

struct dog {};
struct cat {};

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

struct lizard {};

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

Cuando se compila este código, el compilador genera el siguiente result objeto (physicalLocation las propiedades se han quitado por brevedad):

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

El árbol de diagnóstico lógico generado a partir de los mensajes de este result objeto es:

  • 'pet': ninguna función sobrecargada podría convertir todos los tipos de argumento
    • podría ser 'void pet(cat)'
      • 'void pet(cat)': no se puede convertir el argumento 1 de 'lizard' a 'cat'
        • No hay ningún operador de conversión definido por el usuario disponible que pueda realizar esta conversión, o no se puede llamar al operador .
    • o 'void pet(dog)'
      • 'void pet(dog)': no se puede convertir el argumento 1 de 'lizard' a 'dog'
        • No hay ningún operador de conversión definido por el usuario disponible que pueda realizar esta conversión, o no se puede llamar al operador .
    • al intentar coincidir con la lista de argumentos '(lizard)'

Consulte también

/experimental:log (Habilitar diagnósticos de SARIF estructurados)