Поделиться через


Структурированная диагностика SARIF

Компилятор MSVC можно сделать для вывода диагностика как SARIF (формат обмена статическими результатами анализа). SARIF — это формат на основе JSON, доступный для машинного чтения.

Существует два способа создания ДИАГНОСТИКА компилятора MSVC:

  • Передайте переключатель /experimental:log в командной строке. Дополнительные сведения см. в документации /experimental:log .
  • Запустите cl.exe программу и задайте SARIF_OUTPUT_PIPE переменную среды для получения блоков SARIF через канал.

Извлечение SARIF через канал

Средства, использующие SARIF из компилятора MSVC во время компиляции, используют канал. Дополнительные сведения о создании каналов Windows см. в документации CreatePipe .

Чтобы получить SARIF через канал, задайте SARIF_OUTPUT_PIPE переменную среды в виде целого числа HANDLE в кодировке UTF-16 для конца записи, а затем запустите cl.exe. SARIF отправляется по каналу следующим образом:

  • Когда доступна новая диагностика, она записывается в этот канал.
  • Диагностика записывается в канал один раз, а не как весь объект SARIF.
  • Каждая диагностика представлена сообщением JSON-RPC 2.0 типа Notification.
  • Сообщение JSON-RPC префиксируется заголовком с формой Content-Length Content-Length: <N> , за которой следует две новые строки, где <N> длина следующего сообщения JSON-RPC в байтах.
  • Сообщение JSON-RPC и заголовок кодируются в UTF-8.
  • Этот формат JSON-RPC-with-header совместим с vs-streamjsonrpc.
  • Имя метода для вызова OnSarifResultJSON-RPC.
  • Вызов имеет один параметр, закодированный по имени с именем resultпараметра.
  • Значение аргумента — это один result объект, указанный стандартом SARIF версии 2.1.

Пример

Ниже приведен пример результата JSON-RPC SARIF, созданного следующим 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

Компилятор выводит SARIF, который может содержать дополнительные сведения для представления вложенной структуры некоторых диагностика. Диагностика (представленная result объектом SARIF) может содержать "дерево диагностики" дополнительных сведений в своем relatedLocations поле. Это дерево закодировано с помощью контейнера свойств SARIF следующим образом:

location Поле объекта properties может содержать nestingLevel свойство, значение которого — глубина этого расположения в дереве диагностики. Если в расположении нет nestingLevel указанного расположения, глубина считается 0 дочерней из корневой диагностики, представленной result объектом, содержащим его. В противном случае, если значение больше глубины расположения, непосредственно предшествующего этому расположению в relatedLocations поле, это расположение является дочерним элементом этого расположения. В противном случае это расположение является братом ближайшего предыдущего location в relatedLocations поле с той же глубиной.

Пример

Рассмотрим следующий код:

struct dog {};
struct cat {};

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

struct lizard {};

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

При компиляции этого кода компилятор создает следующий result объект (physicalLocation свойства были удалены для краткости):

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

Логическое диагностика дерево, создаваемое из сообщений в этом result объекте:

  • "pet": перегруженная функция не может преобразовать все типы аргументов
    • может быть "void pet(cat)"
      • "void pet(cat)": не может преобразовать аргумент 1 из "ящерица" в "cat"
        • Нет определяемого пользователем оператора преобразования, который может выполнять это преобразование, или не удается вызвать оператор.
    • или "void pet(dog)"
      • "void pet(dog)": не может преобразовать аргумент 1 из "ящерица" в "собака"
        • Нет определяемого пользователем оператора преобразования, который может выполнять это преобразование, или не удается вызвать оператор.
    • при попытке сопоставить список аргументов "(ящерица)"

См. также

/experimental:log(Включение структурированных диагностика SARIF)