[clang] [llvm] [clang][ssaf] Add clang-ssaf-report-merge (PR #235191)

via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 23 19:49:04 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-ssaf

Author: Jan Korous (jkorous-apple)

<details>
<summary>Changes</summary>

A source transformation writes a SARIF report for each translation unit.
Add a tool that merges the reports of the translation units of a link
unit into one, the way clang-ssaf-src-edit-merge merges their edits.

Each report numbers its rules and artifacts on its own, so the tool
renumbers every result against the merged run before it drops the ones
that are identical, such as a finding in a header that several
translation units include. clang lists a run's artifacts in URI order
but numbers them in the order it first refers to them, so an artifact is
known by its own index. The inputs must come from the same
transformation, and a merged report can be merged again.

This relands 07195e29cdba (#<!-- -->231664), reverted with its stack in
782610a701b4 (#<!-- -->232274), under a shorter name:
clang-ssaf-merge-transformation-report took Windows build paths past
MAX_PATH. The GN build files come from 8a96bd506570 (#<!-- -->232114).

Co-authored-by: Kazu Hirata <kazu@<!-- -->google.com>
Assisted-by: Claude



---

Patch is 51.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/235191.diff


25 Files Affected:

- (modified) clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md (+15) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-artifact-index.sarif (+71) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-rule-index.sarif (+71) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/empty.sarif (+21) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/other-transformation.sarif (+21) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-a.sarif (+106) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-b.sarif (+118) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-c.sarif (+71) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-clang-order.sarif (+124) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/two-runs.sarif (+36) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/clang-artifact-order.test (+23) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/cli-errors.test (+87) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/empty.test (+16) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/help.test (+19) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/merge.test (+51) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/nested.test (+16) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/order-invariance.test (+8) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/plugin-reports.test (+47) 
- (added) clang/test/Analysis/Scalable/ssaf-report-merge/version.test (+5) 
- (modified) clang/test/CMakeLists.txt (+1) 
- (modified) clang/tools/CMakeLists.txt (+1) 
- (added) clang/tools/clang-ssaf-report-merge/CMakeLists.txt (+12) 
- (added) clang/tools/clang-ssaf-report-merge/ReportMerge.cpp (+384) 
- (modified) llvm/utils/gn/secondary/clang/test/BUILD.gn (+1) 
- (added) llvm/utils/gn/secondary/clang/tools/clang-ssaf-report-merge/BUILD.gn (+8) 


``````````diff
diff --git a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
index af7fc7f56aa8ca..fb080d7d9d6183 100644
--- a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
+++ b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
@@ -65,3 +65,18 @@ $ clang-apply-replacements --remove-change-desc-files <dir-with-yaml>
 
 The transformation report can be consumed by any SARIF viewer.
 
+
+## Merging transformation reports
+
+A transformation report covers one translation unit. `clang-ssaf-report-merge`
+merges the reports of the translation units of a link unit into one:
+
+```console
+$ clang-ssaf-report-merge foo.sarif bar.sarif -o prg.sarif
+```
+
+The inputs must come from the same transformation. A finding that several
+inputs share, such as one in a header that both translation units include,
+is reported once, and the result does not depend on the order of the
+inputs. A merged report can be merged again.
+
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-artifact-index.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-artifact-index.sarif
new file mode 100644
index 00000000000000..893cd17a4a1b5e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-artifact-index.sarif
@@ -0,0 +1,71 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 120,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/a.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 5,
+                  "uri": "file:///src/a.cpp"
+                },
+                "region": {
+                  "endColumn": 5,
+                  "endLine": 1,
+                  "startColumn": 1,
+                  "startLine": 1
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "declarator spelled through a macro is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-rule-index.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-rule-index.sarif
new file mode 100644
index 00000000000000..093a89d4679239
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/bad-rule-index.sarif
@@ -0,0 +1,71 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 120,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/a.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0,
+                  "uri": "file:///src/a.cpp"
+                },
+                "region": {
+                  "endColumn": 5,
+                  "endLine": 1,
+                  "startColumn": 1,
+                  "startLine": 1
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "declarator spelled through a macro is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 3
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/empty.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/empty.sarif
new file mode 100644
index 00000000000000..944201f0be593f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/empty.sarif
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [],
+      "columnKind": "unicodeCodePoints",
+      "results": [],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/other-transformation.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/other-transformation.sarif
new file mode 100644
index 00000000000000..2a950fd626de57
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/other-transformation.sarif
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [],
+      "columnKind": "unicodeCodePoints",
+      "results": [],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (fix-noexcept)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-a.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-a.sarif
new file mode 100644
index 00000000000000..24a766b14c6050
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-a.sarif
@@ -0,0 +1,106 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 120,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/a.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        },
+        {
+          "length": 60,
+          "location": {
+            "index": 1,
+            "uri": "file:///src/shared.h"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 1,
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "endColumn": 12,
+                  "endLine": 3,
+                  "startColumn": 8,
+                  "startLine": 3
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "multi-level pointer indirection is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        },
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0,
+                  "uri": "file:///src/a.cpp"
+                },
+                "region": {
+                  "endColumn": 7,
+                  "endLine": 7,
+                  "startColumn": 3,
+                  "startLine": 7
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "declarator spelled through a macro is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-b.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-b.sarif
new file mode 100644
index 00000000000000..40d17d8736758c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-b.sarif
@@ -0,0 +1,118 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 60,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/shared.h"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        },
+        {
+          "length": 90,
+          "location": {
+            "index": 1,
+            "uri": "file:///src/b.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0,
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "endColumn": 12,
+                  "endLine": 3,
+                  "startColumn": 8,
+                  "startLine": 3
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "multi-level pointer indirection is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 1
+        },
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 1,
+                  "uri": "file:///src/b.cpp"
+                },
+                "region": {
+                  "endColumn": 5,
+                  "endLine": 5,
+                  "startColumn": 1,
+                  "startLine": 5
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "other finding"
+          },
+          "ruleId": "cpp-bounded-buffers-other",
+          "ruleIndex": 0
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-other",
+              "name": ""
+            },
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-c.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-c.sarif
new file mode 100644
index 00000000000000..51086f43164e99
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-c.sarif
@@ -0,0 +1,71 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 40,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/c.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0,
+                  "uri": "file:///src/c.cpp"
+                },
+                "region": {
+                  "endColumn": 9,
+                  "endLine": 2,
+                  "startColumn": 5,
+                  "startLine": 2
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "multi-level pointer indirection is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-clang-order.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-clang-order.sarif
new file mode 100644
index 00000000000000..8124ebbd875cc5
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/tu-clang-order.sarif
@@ -0,0 +1,124 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "artifacts": [
+        {
+          "length": 120,
+          "location": {
+            "index": 1,
+            "uri": "file:///src/a.cpp"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        },
+        {
+          "length": 60,
+          "location": {
+            "index": 0,
+            "uri": "file:///src/shared.h"
+          },
+          "mimeType": "text/plain",
+          "roles": [
+            "resultFile"
+          ]
+        }
+      ],
+      "columnKind": "unicodeCodePoints",
+      "results": [
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0
+                },
+                "region": {
+                  "endColumn": 12,
+                  "endLine": 3,
+                  "startColumn": 8,
+                  "startLine": 3
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "multi-level pointer indirection is not yet rewritten"
+          },
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        },
+        {
+          "level": "note",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 1,
+                  "uri": "file:///src/a.cpp"
+                },
+                "region": {
+                  "endColumn": 7,
+                  "endLine": 7,
+                  "startColumn": 3,
+                  "startLine": 7
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "declarator spelled through a macro is not yet rewritten"
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "the macro"
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "index": 0
+                },
+                "region": {
+                  "endColumn": 5,
+                  "endLine": 2,
+                  "startColumn": 1,
+                  "startLine": 2
+                }
+              }
+            }
+          ],
+          "ruleId": "cpp-bounded-buffers-skipped",
+          "ruleIndex": 0
+        }
+      ],
+      "tool": {
+        "driver": {
+          "fullName": "clang ScalableStaticAnalysisFramework source transformation (cpp-bounded-buffers)",
+          "informationUri": "https://clang.llvm.org/docs/UsersManual.html",
+          "language": "en-US",
+          "name": "clang-ssaf",
+          "rules": [
+            {
+              "defaultConfiguration": {
+                "enabled": true,
+                "level": "warning",
+                "rank": -1
+              },
+              "fullDescription": {
+                "text": ""
+              },
+              "id": "cpp-bounded-buffers-skipped",
+              "name": ""
+            }
+          ],
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/two-runs.sarif b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/two-runs.sarif
new file mode 100644
index 00000000000000..6fc4646bfe1b73
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-report-merge/Inputs/two-runs.sarif
@@ -0,0 +1,36 @@
+{
+  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-sch...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/235191


More information about the cfe-commits mailing list