Ustrukturyzowana diagnostyka SARIF

Kompilator MSVC można wykonać w celu przeprowadzenia diagnostyki danych wyjściowych jako SARIF (statyczny format wymiany wyników analizy statycznej). SARIF to format oparty na formacie JSON z możliwością odczytu maszynowego.

Istnieją dwa sposoby tworzenia diagnostyki SARIF przez kompilator MSVC:

  • /experimental:log Przekaż przełącznik w wierszu polecenia. Aby uzyskać /experimental:log szczegółowe informacje, zobacz dokumentację.
  • Uruchom cl.exe programowo i ustaw zmienną SARIF_OUTPUT_PIPE środowiskową w celu pobrania bloków SARIF przez potok.

Pobieranie SARIF przez rurę

Narzędzia korzystające z programu SARIF z kompilatora MSVC, gdy kompilacja jest w toku, używają potoku. Zapoznaj się z dokumentacją, aby uzyskać CreatePipe szczegółowe informacje na temat tworzenia potoków systemu Windows.

Aby pobrać sarIF za pośrednictwem potoku, ustaw SARIF_OUTPUT_PIPE zmienną środowiskową jako reprezentację całkowitą HANDLE zakodowaną w formacie UTF-16 na końcu zapisu potoku, a następnie uruchom polecenie cl.exe. PROGRAM SARIF jest wysyłany wzdłuż potoku w następujący sposób:

  • Gdy jest dostępna nowa diagnostyka, jest zapisywana w tym potoku.
  • Diagnostyka jest zapisywana w potoku pojedynczo, a nie jako cały obiekt SARIF.
  • Każda diagnostyka jest reprezentowana przez komunikat JSON-RPC 2.0 typu Powiadomienie.
  • Komunikat JSON-RPC jest poprzedzony nagłówkiem z formularzem Content-LengthContent-Length: <N> , po którym następuje dwa nowe wiersze, gdzie <N> jest długością następującego komunikatu JSON-RPC w bajtach.
  • Komunikat JSON-RPC i nagłówek są kodowane w formacie UTF-8.
  • Ten format JSON-RPC-with-header jest zgodny z plikiem vs-streamjsonrpc.
  • Nazwa metody wywołania JSON-RPC to OnSarifResult.
  • Wywołanie ma jeden parametr zakodowany według nazwy z nazwą resultparametru .
  • Wartość argumentu jest pojedynczym result obiektem określonym przez standard SARIF w wersji 2.1.

Przykład

Oto przykład wyniku SARIF JSON-RPC wygenerowanego przez cl.exeprogram :

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}}}]}}}

Dane wynikowe SARIF

Kompilator zwraca dane wyjściowe SARIF, które mogą zawierać dodatkowe informacje reprezentujące zagnieżdżone struktury niektórych diagnostyki. Diagnostyka (reprezentowana result przez obiekt SARIF) może zawierać "drzewo diagnostyczne" dodatkowych informacji w jego relatedLocations polu. To drzewo jest kodowane przy użyciu torby właściwości SARIF w następujący sposób:

location Pole obiektu properties może zawierać nestingLevel właściwość, której wartość jest głębokością tej lokalizacji w drzewie diagnostycznym. Jeśli lokalizacja nie ma nestingLevel określonej lokalizacji, głębokość jest uważana za 0 i ta lokalizacja jest elementem podrzędnym głównej diagnostyki reprezentowanej przez result obiekt zawierający go. W przeciwnym razie, jeśli wartość jest większa niż głębokość lokalizacji bezpośrednio poprzedzającej tę lokalizację w relatedLocations polu, ta lokalizacja jest elementem podrzędnym tej lokalizacji. W przeciwnym razie lokalizacja jest elementem równorzędnym najbliższego pierwszeństwa location w relatedLocations polu o tej samej głębokości.

Przykład

Spójrzmy na poniższy kod:

struct dog {};
struct cat {};

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

struct lizard {};

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

Po skompilowaniu tego kodu kompilator tworzy następujący result obiekt (physicalLocation właściwości zostały usunięte w celu zwięzłości):

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

Drzewo logicznej diagnostyki wygenerowane z komunikatów w tym result obiekcie to:

  • 'pet': żadna przeciążona funkcja nie może przekonwertować wszystkich typów argumentów
    • może być "void pet(cat)"
      • "void pet(cat)": nie można przekonwertować argumentu 1 z "jaszczurka" na "kot"
        • Brak dostępnego operatora konwersji zdefiniowanego przez użytkownika, który może wykonać tę konwersję, lub nie można wywołać operatora
    • lub "void pet(dog)"
      • "void pet(dog)": nie można przekonwertować argumentu 1 z "jaszczurka" na "psa"
        • Brak dostępnego operatora konwersji zdefiniowanego przez użytkownika, który może wykonać tę konwersję, lub nie można wywołać operatora
    • podczas próby dopasowania listy argumentów "(jaszczurka)"

Zobacz też

/experimental:log (Włącz ustrukturyzowaną diagnostykę SARIF)