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 环境变量设置为管道写入端的 HANDLE 的 UTF-16 编码整数表示形式,然后启动 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。
- 参数的值是 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 字段中紧接在该位置前面的位置的深度,则该位置是紧接在它前面的位置的子位置。 否则,该位置是 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 从“lizard'”转换为“cat” - 没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符
 
 
- “void pet(cat)”:无法将参数 1 从“lizard'”转换为“cat” 
- 或“void pet(dog)” - “void pet(dog)”:无法将参数 1 从“lizard'”转换为“dog” - 没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符
 
 
- “void pet(dog)”:无法将参数 1 从“lizard'”转换为“dog” 
- 尝试匹配参数列表“(lizard)”时
 
- 可能是“void pet(cat)”