結構化 SARIF 診斷
MSVC 編譯程式可以輸出診斷為 SARIF (靜態分析結果交換格式)。 SARIF 是計算機可讀取的 JSON 格式。
有兩種方式可讓 MSVC 編譯程式產生 SARIF 診斷:
- 在
/experimental:log
命令行上傳遞 參數。 如需詳細資訊, 請參閱檔/experimental:log
。 - 以程式設計方式啟動
cl.exe
,SARIF_OUTPUT_PIPE
並設定環境變數,以透過管道擷取 SARIF 區塊。
透過管道擷取 SARIF
編譯進行時,從 MSVC 編譯程式取用 SARIF 的工具會使用管道。 如需建立 Windows 管道的詳細資訊,請參閱檔 CreatePipe
。
若要透過管道擷取 SARIF,請將 SARIF_OUTPUT_PIPE
環境變數設定為 UTF-16 編碼的整數表示 HANDLE
法,以管線的寫入端,然後啟動 cl.exe
。 SARIF 會沿著管道傳送,如下所示:
- 當有新的診斷可用時,它會寫入此管道。
- 診斷會一次一次寫入管道,而不是寫入整個 SARIF 物件。
- 每個診斷都會以通知類型的 JSON-RPC 2.0 訊息來表示。
- JSON-RPC 訊息前面會加上
Content-Length
格式Content-Length: <N>
後面接著兩個新行的標頭,其中<N>
是下列 JSON-RPC 訊息的長度,以位元組為單位。 - JSON-RPC 訊息和標頭都以 UTF-8 編碼。
- 這個 JSON-RPC-with-header 格式與 vs-streamjsonrpc 相容。
- JSON-RPC 呼叫的方法名稱為
OnSarifResult
。 - 呼叫具有以參數名稱
result
編碼的單一參數。 - 自變數的值是 SARIF 2.1 版標準所指定的單
result
一物件。
範例
以下是 由 cl.exe
產生的 JSON-RPC SARIF 結果範例:
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
正前位置的深度,這個位置就是該位置的子系。 否則,這個位置是與相同深度之relatedLocations
字段中最接近前location
方同層級的同層級。
範例
請考慮下列程式碼:
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 從 'lizard' 轉換為 'cat
- 無法執行此轉換的使用者定義轉換運算元,或無法呼叫 運算符
- 'void pet(cat)': 無法將自變數 1 從 'lizard' 轉換為 'cat
- 或 'void pet(dog)'
- “void pet(dog)”: 無法將自變數 1 從 'lizard' 轉換為 'dog'
- 無法執行此轉換的使用者定義轉換運算元,或無法呼叫 運算符
- “void pet(dog)”: 無法將自變數 1 從 'lizard' 轉換為 'dog'
- 嘗試比對自變數清單 '(蜥蜴)'
- 可能是 'void pet(cat)'