llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Jan Korous (jkorous-apple)

<details>
<summary>Changes</summary>

clang-ssaf-src-edit-merge reports the edits it drops because they overlap, but 
only those of the one merge it ran. Add a tool that merges such reports, so 
that the conflicts found while merging the edits of an archive can be carried 
into the report of the program it is linked into.

---

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


19 Files Affected:

- (modified) 
clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md (+12) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-a.sarif
 (+118) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-b.sarif
 (+118) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-c.sarif
 (+67) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/no-conflicts.sarif
 (+15) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/other-tool.sarif 
(+15) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/two-runs.sarif 
(+24) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/cli-errors.test (+69) 
- (added) clang/test/Analysis/Scalable/ssaf-merge-conflict-report/empty.test 
(+14) 
- (added) clang/test/Analysis/Scalable/ssaf-merge-conflict-report/help.test 
(+19) 
- (added) clang/test/Analysis/Scalable/ssaf-merge-conflict-report/merge.test 
(+28) 
- (added) clang/test/Analysis/Scalable/ssaf-merge-conflict-report/nested.test 
(+17) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/order-invariance.test 
(+8) 
- (added) 
clang/test/Analysis/Scalable/ssaf-merge-conflict-report/src-edit-merge-reports.test
 (+26) 
- (added) clang/test/Analysis/Scalable/ssaf-merge-conflict-report/version.test 
(+5) 
- (modified) clang/test/CMakeLists.txt (+1) 
- (modified) clang/tools/CMakeLists.txt (+1) 
- (added) clang/tools/clang-ssaf-merge-conflict-report/CMakeLists.txt (+12) 
- (added) clang/tools/clang-ssaf-merge-conflict-report/MergeConflictReport.cpp 
(+249) 


``````````diff
diff --git 
a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md 
b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
index a0b52b3f7df38..842238730a106 100644
--- a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
+++ b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
@@ -81,3 +81,15 @@ 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.
 
+## Merging conflict reports
+
+`clang-ssaf-src-edit-merge --sarif-conflicts-out=` reports the overlapping
+edits it dropped while merging. `clang-ssaf-merge-conflict-report` merges
+such reports the same way, so that the conflicts found while merging the
+edits of an archive reach the report of the program it is linked into:
+
+```console
+$ clang-ssaf-merge-conflict-report libparse.a.sarif prg.sarif -o all.sarif
+```
+
+The inputs must all have been written by the same tool.
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-a.sarif
 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-a.sarif
new file mode 100644
index 0000000000000..110b144a6d266
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-a.sarif
@@ -0,0 +1,118 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [
+        {
+          "level": "error",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteOffset": 10
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "2 overlapping replacement(s) at file:///src/x.cpp byte 10 
were dropped; resolve manually."
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "candidate edit: \"X\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteLength": 5,
+                  "byteOffset": 10
+                }
+              }
+            },
+            {
+              "id": 2,
+              "message": {
+                "text": "candidate edit: \"Y\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteLength": 3,
+                  "byteOffset": 10
+                }
+              }
+            }
+          ],
+          "ruleId": "clang-reforge-replacement-conflict"
+        },
+        {
+          "level": "error",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteOffset": 4
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "2 overlapping replacement(s) at file:///src/shared.h byte 
4 were dropped; resolve manually."
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "candidate edit: \"int\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteLength": 3,
+                  "byteOffset": 4
+                }
+              }
+            },
+            {
+              "id": 2,
+              "message": {
+                "text": "candidate edit: \"long\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteLength": 4,
+                  "byteOffset": 4
+                }
+              }
+            }
+          ],
+          "ruleId": "clang-reforge-replacement-conflict"
+        }
+      ],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-b.sarif
 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-b.sarif
new file mode 100644
index 0000000000000..7a7a92bb92921
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-b.sarif
@@ -0,0 +1,118 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [
+        {
+          "level": "error",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteOffset": 4
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "2 overlapping replacement(s) at file:///src/shared.h byte 
4 were dropped; resolve manually."
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "candidate edit: \"int\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteLength": 3,
+                  "byteOffset": 4
+                }
+              }
+            },
+            {
+              "id": 2,
+              "message": {
+                "text": "candidate edit: \"long\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/shared.h"
+                },
+                "region": {
+                  "byteLength": 4,
+                  "byteOffset": 4
+                }
+              }
+            }
+          ],
+          "ruleId": "clang-reforge-replacement-conflict"
+        },
+        {
+          "level": "error",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/y.cpp"
+                },
+                "region": {
+                  "byteOffset": 30
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "2 overlapping replacement(s) at file:///src/y.cpp byte 30 
were dropped; resolve manually."
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "candidate edit: \"Q\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/y.cpp"
+                },
+                "region": {
+                  "byteLength": 2,
+                  "byteOffset": 30
+                }
+              }
+            },
+            {
+              "id": 2,
+              "message": {
+                "text": "candidate edit: \"Z\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/y.cpp"
+                },
+                "region": {
+                  "byteLength": 2,
+                  "byteOffset": 30
+                }
+              }
+            }
+          ],
+          "ruleId": "clang-reforge-replacement-conflict"
+        }
+      ],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-c.sarif
 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-c.sarif
new file mode 100644
index 0000000000000..dc5b1c020be8d
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/conflicts-c.sarif
@@ -0,0 +1,67 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [
+        {
+          "level": "error",
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteOffset": 2
+                }
+              }
+            }
+          ],
+          "message": {
+            "text": "2 overlapping replacement(s) at file:///src/x.cpp byte 2 
were dropped; resolve manually."
+          },
+          "relatedLocations": [
+            {
+              "id": 1,
+              "message": {
+                "text": "candidate edit: \"A\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteLength": 1,
+                  "byteOffset": 2
+                }
+              }
+            },
+            {
+              "id": 2,
+              "message": {
+                "text": "candidate edit: \"B\""
+              },
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///src/x.cpp"
+                },
+                "region": {
+                  "byteLength": 1,
+                  "byteOffset": 2
+                }
+              }
+            }
+          ],
+          "ruleId": "clang-reforge-replacement-conflict"
+        }
+      ],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/no-conflicts.sarif
 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/no-conflicts.sarif
new file mode 100644
index 0000000000000..da2d8c6941462
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/no-conflicts.sarif
@@ -0,0 +1,15 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/other-tool.sarif
 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/other-tool.sarif
new file mode 100644
index 0000000000000..1c2ea28ea3ad4
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/other-tool.sarif
@@ -0,0 +1,15 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/two-runs.sarif 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/two-runs.sarif
new file mode 100644
index 0000000000000..cda78d1c4282d
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/Inputs/two-runs.sarif
@@ -0,0 +1,24 @@
+{
+  "$schema": "https://json.schemastore.org/sarif-2.1.0.json";,
+  "runs": [
+    {
+      "results": [],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    },
+    {
+      "results": [],
+      "tool": {
+        "driver": {
+          "name": "clang-ssaf-src-edit-merge",
+          "version": "24.0.0git"
+        }
+      }
+    }
+  ],
+  "version": "2.1.0"
+}
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/cli-errors.test 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/cli-errors.test
new file mode 100644
index 0000000000000..05a17c2f6cfab
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/cli-errors.test
@@ -0,0 +1,69 @@
+// Tests for clang-ssaf-merge-conflict-report errors.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// CLI error: no arguments
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=NO-ARGS
+// NO-ARGS: clang-ssaf-merge-conflict-report{{(\.exe)?}}: Not enough 
positional command line arguments specified!
+
+// ============================================================================
+// CLI error: missing -o
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=NO-OUTPUT
+// NO-OUTPUT: clang-ssaf-merge-conflict-report{{(\.exe)?}}: for the -o option: 
must be specified at least once!
+
+// ============================================================================
+// Error: nonexistent input
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report %t/missing.sarif \
+// RUN:   -o %t/out.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MISSING -DPATH=%t/missing.sarif
+// MISSING: clang-ssaf-merge-conflict-report: error: failed to read 
'[[PATH]]': {{.*}}
+
+// ============================================================================
+// Error: input is not JSON
+// ============================================================================
+
+// RUN: echo 'not json' > %t/not-json.sarif
+// RUN: not clang-ssaf-merge-conflict-report %t/not-json.sarif \
+// RUN:   -o %t/out.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=NOT-JSON -DPATH=%t/not-json.sarif
+// NOT-JSON: clang-ssaf-merge-conflict-report: error: failed to parse 
'[[PATH]]': {{.*}}
+
+// ============================================================================
+// Error: input does not have exactly one run
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report %S/Inputs/two-runs.sarif \
+// RUN:   -o %t/out.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=TWO-RUNS
+// TWO-RUNS: clang-ssaf-merge-conflict-report: error: '{{.*}}two-runs.sarif' 
is not a SARIF log with exactly one run
+
+// ============================================================================
+// Error: inputs written by different tools
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif \
+// RUN:   %S/Inputs/other-tool.sarif -o %t/out.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=OTHER
+// OTHER: clang-ssaf-merge-conflict-report: error: '{{.*}}other-tool.sarif' 
was written by 'clang-ssaf', not by 'clang-ssaf-src-edit-merge'
+
+// ============================================================================
+// Error: the output cannot be written
+// ============================================================================
+
+// RUN: not clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif \
+// RUN:   -o %t/no-such-dir/out.sarif 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CANNOT-WRITE 
-DPATH=%t/no-such-dir/out.sarif
+// CANNOT-WRITE: clang-ssaf-merge-conflict-report: error: failed to write 
'[[PATH]]': {{.*}}
+
+// No error leaves an output behind.
+// RUN: not ls %t/out.sarif
diff --git a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/empty.test 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/empty.test
new file mode 100644
index 0000000000000..948cdfd95cedd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/empty.test
@@ -0,0 +1,14 @@
+// Reports without conflicts merge into a report without conflicts, and add
+// nothing to a report that has some.
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: clang-ssaf-merge-conflict-report %S/Inputs/no-conflicts.sarif \
+// RUN:   %S/Inputs/no-conflicts.sarif -o %t/none.sarif
+// RUN: FileCheck %s --input-file=%t/none.sarif
+// CHECK: "results": [],
+
+// RUN: clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif \
+// RUN:   -o %t/a.sarif
+// RUN: clang-ssaf-merge-conflict-report %S/Inputs/no-conflicts.sarif \
+// RUN:   %S/Inputs/conflicts-a.sarif -o %t/none-a.sarif
+// RUN: diff %t/a.sarif %t/none-a.sarif
diff --git a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/help.test 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/help.test
new file mode 100644
index 0000000000000..c8f0884255f9c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/help.test
@@ -0,0 +1,19 @@
+// Test clang-ssaf-merge-conflict-report help option
+
+// RUN: clang-ssaf-merge-conflict-report --help-list-hidden \
+// RUN:           | FileCheck %s --match-full-lines
+
+// CHECK:      OVERVIEW: SSAF Conflict Report Merger
+// CHECK-EMPTY:
+// CHECK-NEXT: USAGE: clang-ssaf-merge-conflict-report{{(\.exe)?}} [options] 
<input.sarif>...
+// CHECK-EMPTY:
+// CHECK-NEXT: OPTIONS:
+// CHECK-NEXT:   -h                  - Alias for --help
+// CHECK-NEXT:   --help              - Display available options 
(--help-hidden for more)
+// CHECK-NEXT:   --help-hidden       - Display all available options
+// CHECK-NEXT:   --help-list         - Display list of available options 
(--help-list-hidden for more)
+// CHECK-NEXT:   --help-list-hidden  - Display list of all available options
+// CHECK-NEXT:   -o <path>           - Output file path
+// CHECK-NEXT:   --print-all-options - Print all option values after command 
line parsing
+// CHECK-NEXT:   --print-options     - Print non-default options after command 
line parsing
+// CHECK-NEXT:   --version           - Display the version of this program
diff --git a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/merge.test 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/merge.test
new file mode 100644
index 0000000000000..e54317ff9b809
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/merge.test
@@ -0,0 +1,28 @@
+// Two conflict reports that share a conflict merge into one run.
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif \
+// RUN:   %S/Inputs/conflicts-b.sarif -o %t/merged.sarif
+// RUN: FileCheck %s --input-file=%t/merged.sarif
+
+// '-' writes the report to stdout.
+// RUN: clang-ssaf-merge-conflict-report %S/Inputs/conflicts-a.sarif \
+// RUN:   %S/Inputs/conflicts-b.sarif -o - > %t/stdout.sarif
+// RUN: diff %t/merged.sarif %t/stdout.sarif
+// RUN: grep '"text": "2 overlapping replacement(s) at file:///src/shared.h' \
+// RUN:   %t/merged.sarif | count 1
+
+// The conflicts in location order, the shared one once.
+// CHECK:      "results": [
+// CHECK:        "uri": "file:///src/shared.h"
+// CHECK:        "byteOffset": 4
+// CHECK:        "text": "2 overlapping replacement(s) at file:///src/shared.h 
byte 4 were dropped; resolve manually."
+// CHECK:        "text": "candidate edit: \"int\""
+// CHECK:        "text": "candidate edit: \"long\""
+// CHECK:        "uri": "file:///src/x.cpp"
+// CHECK:        "byteOffset": 10
+// CHECK:        "uri": "file:///src/y.cpp"
+// CHECK:        "byteOffset": 30
+// CHECK:      "tool": {
+// CHECK:        "name": "clang-ssaf-src-edit-merge",
+// CHECK:      "version": "2.1.0"
diff --git 
a/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/nested.test 
b/clang/test/Analysis/Scalable/ssaf-merge-conflict-report/nested.test
new file mode 100644
index 0000000000000..7f7bce20c8dac
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-m...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/231731
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to