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-Length
Content-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ą
result
parametru . - 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.exe
program :
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
- "void pet(cat)": nie można przekonwertować argumentu 1 z "jaszczurka" na "kot"
- 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
- "void pet(dog)": nie można przekonwertować argumentu 1 z "jaszczurka" na "psa"
- podczas próby dopasowania listy argumentów "(jaszczurka)"
- może być "void pet(cat)"
Zobacz też
/experimental:log
(Włącz ustrukturyzowaną diagnostykę SARIF)