次の方法で共有


構造化された SARIF 診断

MSVC コンパイラは、診断を SARIF (静的分析結果交換形式) として出力できます。 SARIF は、マシンで読み取り可能な JSON ベースの形式です。

MSVC コンパイラで SARIF 診断を生成するには、次の 2 つの方法があります。

  • /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 オブジェクト全体としてではなく、一度に 1 つずつパイプに書き込まれます。
  • 各診断は、NotificationJSON-RPC 2.0 メッセージで表されます。
  • JSON-RPC メッセージの先頭 Content-Length にヘッダーが付き、その後 Content-Length: <N> に 2 つの改行が続きます。これは <N> 、次の JSON-RPC メッセージの長さ (バイト単位) です。
  • JSON-RPC メッセージとヘッダーはどちらも UTF-8 でエンコードされます。
  • この JSON-RPC-with-header 形式は vs-streamjsonrpc互換性があります。
  • JSON-RPC 呼び出しのメソッド名は .OnSarifResult
  • この呼び出しには、パラメーター名でエンコードされたパラメーターが 1 つ含まれますresult
  • 引数の値は、SARIF バージョン 2.1 標準指定されている 1 つのresultオブジェクトです。

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 を出力します。 診断 (SARIF オブジェクトで result 表される) には、そのフィールドに追加情報 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(dog)'
      • 'void pet(dog)': 引数 1 を 'lizard' から 'dog' に変換できません
        • この変換を実行できるユーザー定義変換演算子がない、または演算子を呼び出すことができない
    • 引数リスト '(lizard)' と一致しようとしています

関連項目

/experimental:log(構造化された SARIF 診断を有効にする)