Partilhar via


Diagnóstico SARIF estruturado

O compilador MSVC pode ser feito para diagnóstico de saída como SARIF (Static Analysis Results Interchange Format). SARIF é um formato baseado em JSON legível por máquina.

Há duas maneiras de fazer o compilador MSVC produzir diagnósticos SARIF:

  • Passe o /experimental:log interruptor na linha de comando. Consulte a documentação para /experimental:log obter detalhes.
  • Inicie cl.exe programaticamente e defina a SARIF_OUTPUT_PIPE variável de ambiente para recuperar blocos SARIF através de um pipe.

Recuperando SARIF através de um tubo

As ferramentas que consomem SARIF do compilador MSVC enquanto uma compilação está em andamento usam um pipe. Consulte a documentação para CreatePipe obter detalhes sobre a criação de pipes do Windows.

Para recuperar SARIF através de um pipe, defina a SARIF_OUTPUT_PIPE variável de ambiente como sendo a HANDLE representação inteira codificada em UTF-16 do para a extremidade de gravação do pipe e, em seguida, inicie cl.exe. SARIF é enviado ao longo do tubo da seguinte forma:

  • Quando um novo diagnóstico está disponível, ele é gravado neste tubo.
  • Os diagnósticos são gravados no pipe um de cada vez, em vez de como um objeto SARIF inteiro.
  • Cada diagnóstico é representado por uma mensagem JSON-RPC 2.0 do tipo Notification.
  • A mensagem JSON-RPC é prefixada com um Content-Length cabeçalho com o formulário Content-Length: <N> seguido por duas novas linhas, onde <N> é o comprimento da seguinte mensagem JSON-RPC em bytes.
  • A mensagem JSON-RPC e o cabeçalho são ambos codificados em UTF-8.
  • Este formato JSON-RPC-with-header é compatível com vs-streamjsonrpc.
  • O nome do método para a chamada JSON-RPC é OnSarifResult.
  • A chamada tem um único parâmetro que é codificado por nome com o nome resultdo parâmetro .
  • O valor do argumento é um único result objeto, conforme especificado pelo padrão SARIF Versão 2.1.

Exemplo

Aqui está um exemplo de um resultado SARIF JSON-RPC produzido 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}}}]}}}

Dados dos resultados SARIF

O compilador produz SARIF que podem incluir informações adicionais para representar a estrutura aninhada de alguns diagnósticos. Um diagnóstico (representado por um result objeto SARIF) pode conter uma "árvore de diagnóstico" de informações adicionais em seu relatedLocations campo. Esta árvore é codificada usando um saco de propriedades SARIF da seguinte maneira:

O campo de location um properties objeto pode conter uma nestingLevel propriedade cujo valor é a profundidade desse local na árvore de diagnóstico. Se um local não tiver um nestingLevel especificado, a profundidade será considerada como sendo 0 e esse local será filho do diagnóstico raiz representado pelo result objeto que o contém. Caso contrário, se o valor for maior do que a profundidade do local imediatamente anterior a relatedLocations esse local no campo, esse local será filho desse local. Caso contrário, este local é um irmão do anterior location mais próximo no relatedLocations campo com a mesma profundidade.

Exemplo

Considere o seguinte código:

struct dog {};
struct cat {};

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

struct lizard {};

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

Quando esse código é compilado, o compilador produz o seguinte result objeto (physicalLocation as propriedades foram removidas para brevidade):

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

A árvore de diagnóstico lógico produzida a partir das mensagens neste result objeto é:

  • 'pet': nenhuma função sobrecarregada poderia converter todos os tipos de argumento
    • poderia ser 'animal de estimação vazio (gato)'
      • 'Void Pet(Cat)': Não é possível converter o argumento 1 de 'Lagarto' para 'Gato
        • Nenhum operador de conversão definido pelo usuário disponível que possa executar essa conversão, ou o operador não pode ser chamado
    • ou 'animal de estimação vazio (cão)'
      • 'Void Pet(Dog)': Não é possível converter o argumento 1 de 'lagarto' para 'cão'
        • Nenhum operador de conversão definido pelo usuário disponível que possa executar essa conversão, ou o operador não pode ser chamado
    • ao tentar corresponder à lista de argumentos '(lagarto)'

Ver também

/experimental:log (Ativar diagnóstico SARIF estruturado)