[clang] [clang][ssaf] Make TUSummary and LUSummary JSON representations self-describing (PR #204409)

Aviral Goel via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 17 13:54:37 PDT 2026


https://github.com/aviralg updated https://github.com/llvm/llvm-project/pull/204409

>From 6364a60adb9f4bca05458deb8f25e479b0a866db Mon Sep 17 00:00:00 2001
From: Aviral Goel <goel.aviral at gmail.com>
Date: Wed, 17 Jun 2026 11:19:30 -0700
Subject: [PATCH 1/4] Update json files

---
 .../Scalable/PointerFlow/Inputs/tu-summary-bad-array.json      | 3 ++-
 .../Scalable/PointerFlow/Inputs/tu-summary-bad-summary.json    | 3 ++-
 .../Scalable/PointerFlow/Inputs/tu-summary-no-key.json         | 3 ++-
 .../test/Analysis/Scalable/PointerFlow/Inputs/tu-summary.json  | 3 ++-
 .../UnsafeBufferUsage/Inputs/tu-summary-bad-element.json       | 3 ++-
 .../UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json     | 3 ++-
 .../Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json   | 3 ++-
 .../Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json | 3 ++-
 .../Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json   | 3 ++-
 clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json      | 3 ++-
 .../Inputs/CallGraph/invalid-direct-callee-element.json        | 3 ++-
 .../ssaf-format/Inputs/CallGraph/invalid-direct-callee-id.json | 3 ++-
 .../Scalable/ssaf-format/Inputs/CallGraph/missing-def-col.json | 3 ++-
 .../ssaf-format/Inputs/CallGraph/missing-def-file.json         | 3 ++-
 .../ssaf-format/Inputs/CallGraph/missing-def-line.json         | 3 ++-
 .../Scalable/ssaf-format/Inputs/CallGraph/missing-def.json     | 3 ++-
 .../ssaf-format/Inputs/CallGraph/missing-direct-callees.json   | 3 ++-
 .../ssaf-format/Inputs/CallGraph/missing-pretty-name.json      | 3 ++-
 .../ssaf-format/Inputs/CallGraph/missing-virtual-callees.json  | 3 ++-
 .../ssaf-format/LUSummary/Inputs/data-element-not-object.json  | 3 ++-
 .../ssaf-format/LUSummary/Inputs/data-entry-missing-data.json  | 3 ++-
 .../LUSummary/Inputs/data-entry-missing-summary-name.json      | 3 ++-
 .../Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json  | 3 ++-
 .../LUSummary/Inputs/duplicate-entity-id-in-data-map.json      | 3 ++-
 .../ssaf-format/LUSummary/Inputs/duplicate-entity.json         | 3 ++-
 .../ssaf-format/LUSummary/Inputs/duplicate-summary-name.json   | 3 ++-
 .../LUSummary/Inputs/entity-data-element-not-object.json       | 3 ++-
 .../LUSummary/Inputs/entity-data-missing-entity-id.json        | 3 ++-
 .../LUSummary/Inputs/entity-data-missing-entity-summary.json   | 3 ++-
 .../ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json     | 3 ++-
 .../LUSummary/Inputs/entity-name-missing-namespace.json        | 3 ++-
 .../LUSummary/Inputs/entity-name-missing-suffix.json           | 3 ++-
 .../ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json  | 3 ++-
 .../LUSummary/Inputs/id-table-element-not-object.json          | 3 ++-
 .../LUSummary/Inputs/id-table-entry-id-not-uint64.json         | 3 ++-
 .../LUSummary/Inputs/id-table-entry-missing-id.json            | 3 ++-
 .../LUSummary/Inputs/id-table-entry-missing-name.json          | 3 ++-
 .../ssaf-format/LUSummary/Inputs/id-table-not-array.json       | 3 ++-
 .../LUSummary/Inputs/linkage-table-duplicate-id.json           | 3 ++-
 .../LUSummary/Inputs/linkage-table-element-not-object.json     | 3 ++-
 .../LUSummary/Inputs/linkage-table-entry-id-not-uint64.json    | 3 ++-
 .../Inputs/linkage-table-entry-linkage-invalid-type.json       | 3 ++-
 .../Inputs/linkage-table-entry-linkage-missing-type.json       | 3 ++-
 .../LUSummary/Inputs/linkage-table-entry-missing-id.json       | 3 ++-
 .../LUSummary/Inputs/linkage-table-entry-missing-linkage.json  | 3 ++-
 .../ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json   | 3 ++-
 .../ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json | 3 ++-
 .../ssaf-format/LUSummary/Inputs/linkage-table-not-array.json  | 3 ++-
 .../LUSummary/Inputs/lu-namespace-element-invalid-kind.json    | 3 ++-
 .../LUSummary/Inputs/lu-namespace-element-missing-kind.json    | 3 ++-
 .../LUSummary/Inputs/lu-namespace-element-missing-name.json    | 3 ++-
 .../LUSummary/Inputs/lu-namespace-element-not-object.json      | 3 ++-
 .../ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json   | 3 ++-
 .../Scalable/ssaf-format/LUSummary/Inputs/missing-data.json    | 3 ++-
 .../ssaf-format/LUSummary/Inputs/missing-id-table.json         | 3 ++-
 .../ssaf-format/LUSummary/Inputs/missing-linkage-table.json    | 3 ++-
 .../ssaf-format/LUSummary/Inputs/missing-lu-namespace.json     | 3 ++-
 .../ssaf-format/LUSummary/Inputs/missing-target-triple.json    | 3 ++-
 .../LUSummary/Inputs/namespace-element-invalid-kind.json       | 3 ++-
 .../LUSummary/Inputs/namespace-element-missing-kind.json       | 3 ++-
 .../LUSummary/Inputs/namespace-element-missing-name.json       | 3 ++-
 .../LUSummary/Inputs/namespace-element-not-object.json         | 3 ++-
 .../LUSummary/Inputs/not-normalized-target-triple.json         | 3 ++-
 .../ssaf-format/LUSummary/Inputs/pairs-element-not-object.json | 3 ++-
 .../LUSummary/Inputs/pairs-invalid-first-field.json            | 3 ++-
 .../LUSummary/Inputs/pairs-invalid-pairs-field-type.json       | 3 ++-
 .../LUSummary/Inputs/pairs-invalid-second-field.json           | 3 ++-
 .../LUSummary/Inputs/pairs-missing-first-field.json            | 3 ++-
 .../LUSummary/Inputs/pairs-missing-pairs-field.json            | 3 ++-
 .../LUSummary/Inputs/pairs-missing-second-field.json           | 3 ++-
 .../LUSummary/Inputs/read-entity-summary-no-format-info.json   | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json      | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-empty-namespace.json       | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-linkage-external.json      | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-linkage-internal.json      | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json      | 3 ++-
 .../Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json | 3 ++-
 .../LUSummary/Inputs/rt-multiple-namespace-elements.json       | 3 ++-
 .../LUSummary/Inputs/rt-single-namespace-element.json          | 3 ++-
 .../ssaf-format/LUSummary/Inputs/rt-two-summary-types.json     | 3 ++-
 .../ssaf-format/TUSummary/Inputs/data-element-not-object.json  | 3 ++-
 .../ssaf-format/TUSummary/Inputs/data-entry-missing-data.json  | 3 ++-
 .../TUSummary/Inputs/data-entry-missing-summary-name.json      | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json  | 3 ++-
 .../TUSummary/Inputs/duplicate-entity-id-in-data-map.json      | 3 ++-
 .../ssaf-format/TUSummary/Inputs/duplicate-entity.json         | 3 ++-
 .../ssaf-format/TUSummary/Inputs/duplicate-summary-name.json   | 3 ++-
 .../TUSummary/Inputs/entity-data-element-not-object.json       | 3 ++-
 .../TUSummary/Inputs/entity-data-missing-entity-id.json        | 3 ++-
 .../TUSummary/Inputs/entity-data-missing-entity-summary.json   | 3 ++-
 .../ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json     | 3 ++-
 .../TUSummary/Inputs/entity-name-missing-suffix.json           | 3 ++-
 .../ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json  | 3 ++-
 .../TUSummary/Inputs/id-table-element-not-object.json          | 3 ++-
 .../TUSummary/Inputs/id-table-entry-id-not-uint64.json         | 3 ++-
 .../TUSummary/Inputs/id-table-entry-missing-id.json            | 3 ++-
 .../TUSummary/Inputs/id-table-entry-missing-name.json          | 3 ++-
 .../ssaf-format/TUSummary/Inputs/id-table-not-array.json       | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json    | 3 ++-
 .../TUSummary/Inputs/linkage-table-duplicate-id.json           | 3 ++-
 .../TUSummary/Inputs/linkage-table-element-not-object.json     | 3 ++-
 .../TUSummary/Inputs/linkage-table-entry-id-not-uint64.json    | 3 ++-
 .../Inputs/linkage-table-entry-linkage-invalid-type.json       | 3 ++-
 .../Inputs/linkage-table-entry-linkage-missing-type.json       | 3 ++-
 .../TUSummary/Inputs/linkage-table-entry-missing-id.json       | 3 ++-
 .../TUSummary/Inputs/linkage-table-entry-missing-linkage.json  | 3 ++-
 .../ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json   | 3 ++-
 .../ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json | 3 ++-
 .../ssaf-format/TUSummary/Inputs/linkage-table-not-array.json  | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/missing-data.json    | 3 ++-
 .../ssaf-format/TUSummary/Inputs/missing-id-table.json         | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json    | 3 ++-
 .../ssaf-format/TUSummary/Inputs/missing-linkage-table.json    | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/missing-name.json    | 3 ++-
 .../ssaf-format/TUSummary/Inputs/missing-target-triple.json    | 3 ++-
 .../ssaf-format/TUSummary/Inputs/missing-tu-namespace.json     | 3 ++-
 .../TUSummary/Inputs/not-normalized-target-triple.json         | 3 ++-
 .../ssaf-format/TUSummary/Inputs/pairs-element-not-object.json | 3 ++-
 .../TUSummary/Inputs/pairs-invalid-first-field.json            | 3 ++-
 .../TUSummary/Inputs/pairs-invalid-pairs-field-type.json       | 3 ++-
 .../TUSummary/Inputs/pairs-invalid-second-field.json           | 3 ++-
 .../TUSummary/Inputs/pairs-missing-first-field.json            | 3 ++-
 .../TUSummary/Inputs/pairs-missing-pairs-field.json            | 3 ++-
 .../TUSummary/Inputs/pairs-missing-second-field.json           | 3 ++-
 .../TUSummary/Inputs/read-entity-summary-no-format-info.json   | 3 ++-
 .../ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json      | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json        | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json    | 3 ++-
 .../ssaf-format/TUSummary/Inputs/rt-linkage-external.json      | 3 ++-
 .../ssaf-format/TUSummary/Inputs/rt-linkage-internal.json      | 3 ++-
 .../ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json      | 3 ++-
 .../Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json | 3 ++-
 .../ssaf-format/TUSummary/Inputs/rt-two-summary-types.json     | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-1.json      | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-2.json      | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-empty.json  | 3 ++-
 .../ssaf-linker/Inputs/tu-invalid-entity-id-multikey.json      | 3 ++-
 .../Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-ref.json  | 3 ++-
 .../ssaf-linker/Inputs/tu-invalid-entity-id-value.json         | 3 ++-
 .../Scalable/ssaf-linker/Inputs/tu-missing-fields.json         | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json   | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json     | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json     | 3 ++-
 clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-empty.json | 3 ++-
 144 files changed, 288 insertions(+), 144 deletions(-)

diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-array.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-array.json
index 3e7424018cb82..282917559e5b5 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-array.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-array.json
@@ -85,5 +85,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-summary.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-summary.json
index f84843491c743..c2c5e119ca330 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-summary.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-bad-summary.json
@@ -62,5 +62,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-no-key.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-no-key.json
index 33cc2462333f1..14c654f8b7c14 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-no-key.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary-no-key.json
@@ -91,5 +91,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary.json
index 86d412c521fcf..9b0b4575e2f61 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/tu-summary.json
@@ -88,5 +88,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
index dbad76015b28b..8e73183ce3b29 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
@@ -48,5 +48,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
index 85522f074fa05..9a4ef04219f0a 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
@@ -53,5 +53,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
index f08db537807eb..0ab350fa56182 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
@@ -53,5 +53,6 @@
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
index c50a22faf5bf8..e4df108408472 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
@@ -102,5 +102,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "Mock.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json
index 5a4a6205efab7..ddff7a789fffb 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json
@@ -41,5 +41,6 @@
       "name": "test.exe"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json
index 86b2e5184588c..4654ada97a341 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json
@@ -123,5 +123,6 @@
       "name": "test.exe"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-element.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-element.json
index a644df1ca8bfe..b726ec997917f 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-element.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-element.json
@@ -37,5 +37,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-id.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-id.json
index 209ae4a9179ab..c4d8af0dbfcfc 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/invalid-direct-callee-id.json
@@ -39,5 +39,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-col.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-col.json
index 7caf5142b627a..fb928fe397acc 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-col.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-col.json
@@ -39,5 +39,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-file.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-file.json
index d7f23575d1761..e43509f1f8ca4 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-file.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-file.json
@@ -36,5 +36,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-line.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-line.json
index 0cdab50c2c94e..dd14915d37aba 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-line.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def-line.json
@@ -38,5 +38,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def.json
index cb0bc5da020dd..c0da9cd05f807 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-def.json
@@ -35,5 +35,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-direct-callees.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-direct-callees.json
index 8cb06de4ab32c..45262d5813200 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-direct-callees.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-direct-callees.json
@@ -33,5 +33,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-pretty-name.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-pretty-name.json
index 4bc14754457be..b1e7de381a36a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-pretty-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-pretty-name.json
@@ -31,5 +31,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-virtual-callees.json b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-virtual-callees.json
index 60732ea628acc..02e313bdc67b0 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-virtual-callees.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/Inputs/CallGraph/missing-virtual-callees.json
@@ -34,5 +34,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
index 75d44b793a7e7..dc1aecd86683e 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
@@ -10,5 +10,6 @@
   "data": [
     "invalid"
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
index 5cd6cf276e9b8..c7c70a5838efc 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
@@ -12,5 +12,6 @@
       "summary_name": "PairsEntitySummary"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
index 78b5860527310..c4234534261db 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
@@ -12,5 +12,6 @@
       "summary_data": []
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
index bd7ec6b5c692f..68a5efddea138 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
@@ -8,5 +8,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": {},
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
index 72dbc7653dce4..08bda0ffa6c73 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
@@ -51,5 +51,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
index 3866aa96530a4..0d5e7d5b1eeec 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
@@ -56,5 +56,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
index 208ec9fae45c3..04efe47d41cee 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
@@ -17,5 +17,6 @@
       "summary_data": []
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
index 33f3dd29d4eef..9c17365ea1916 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
@@ -15,5 +15,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
index 74aebdfef6a01..498a6c8359fa9 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
@@ -17,5 +17,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
index 169d57a05bcf6..cc8f8a331a466 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
@@ -17,5 +17,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
index f31489f30385d..302674eacc912 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
@@ -18,5 +18,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
index ad6cddb741090..174423ce72c33 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
@@ -23,5 +23,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
index 41126fa4d9247..92457c7f75d44 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
@@ -28,5 +28,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
index b46d6d2742271..a3af210d887b1 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
@@ -32,5 +32,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
index 94c9de273a8d9..acaa0feb24d25 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
@@ -10,5 +10,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
index 729c2aa051148..cf31a7ba25106 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
@@ -26,5 +26,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
index d3b16784657fb..193b036461f1c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
@@ -25,5 +25,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
index 3cb574f405837..54bef9ba275a9 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
@@ -12,5 +12,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
index 080e151b7a96d..80ae213169a43 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
@@ -8,5 +8,6 @@
   "id_table": {},
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
index cecfba5a49ff4..e03fa76057044 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
@@ -39,5 +39,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
index f0aefb3e9683c..7345dae82c552 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
@@ -10,5 +10,6 @@
     "invalid"
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
index 036f7de66a415..ae30fe240fb20 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
@@ -15,5 +15,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
index 407572bc5b572..7f53e39f1d942 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
@@ -15,5 +15,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
index 7961ef2a2e630..d52f40c4fda2d 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
@@ -13,5 +13,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
index 7fa7f469f2385..73738e0a42255 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
@@ -14,5 +14,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
index 9b2b9458506d8..32f3e0c84b863 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
@@ -12,5 +12,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
index c0ab2322f6ba4..af1436f97df13 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
@@ -15,5 +15,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
index 2f47753afb1d2..e0e299d938ec7 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
@@ -26,5 +26,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
index 11ddd41feb3ec..05d8503262109 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
@@ -8,5 +8,6 @@
   "id_table": [],
   "linkage_table": {},
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
index 25819336f165c..42bf456dbe99a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
@@ -8,5 +8,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
index 61adde1614a5d..875285cde50c1 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
@@ -7,5 +7,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
index f1b69104429c9..9f0bf4c24032a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
@@ -7,5 +7,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
index 96adf4830c753..6d222ed27029b 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
@@ -5,5 +5,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
index f357bb793ca2e..88d7643a6eb83 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
index 2016767c7905f..bcf22838ce522 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
@@ -7,5 +7,6 @@
   ],
   "id_table": [],
   "linkage_table": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
index dbd255a71a17a..764ce701287b5 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
@@ -6,5 +6,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
index 3b5f4308136ca..cb85ce147e4a0 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
@@ -7,5 +7,6 @@
   ],
   "id_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
index ed207878fae11..0f537c6665894 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
@@ -2,5 +2,6 @@
   "target_triple": "arm64-apple-macosx",
   "id_table": [],
   "linkage_table": [],
-  "data": []
+  "data": [],
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-target-triple.json
index 55ed383c14f17..765a8b8b2f703 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-target-triple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-target-triple.json
@@ -7,5 +7,6 @@
       "kind": "LinkUnit",
       "name": "test.exe"
     }
-  ]
+  ],
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
index b1b6af46d6d8e..6c648ca818656 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
@@ -29,5 +29,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
index cbcce067df087..004ff880ab480 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
@@ -28,5 +28,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
index f3da73e38ba19..b35b6bb00da4b 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
@@ -28,5 +28,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
index a0bfe0fde0756..00f88a4651d90 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
@@ -26,5 +26,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-normalized-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-normalized-target-triple.json
index fc936aaf17d97..6ecdeef56e55a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-normalized-target-triple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-normalized-target-triple.json
@@ -8,5 +8,6 @@
       "name": "test.exe"
     }
   ],
-  "target_triple": "arm64-macosx-apple"
+  "target_triple": "arm64-macosx-apple",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
index 1679bd0c68f5d..7bc19afa5e943 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
@@ -22,5 +22,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
index 74fcc325a8a49..72e7545626f90 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
@@ -27,5 +27,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
index 3be0b80ab524a..801de7d969b2a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
@@ -20,5 +20,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
index 95250febb3484..2b5b2fd87a763 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
@@ -27,5 +27,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
index 29c7879072929..62897d2e5ce73 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
@@ -26,5 +26,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
index f8ce6042ef6a5..d71c7fa96431d 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
@@ -18,5 +18,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
index 702e5ee462559..23459d00e76d6 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
@@ -26,5 +26,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
index fed0e1d3d8aec..63989f69371fd 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
@@ -18,5 +18,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
\ No newline at end of file
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
index 38d7adb40274f..cf8124d999f7f 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
@@ -13,5 +13,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
index fc8c51a7aab2c..d3c64b8d3eaf3 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
@@ -8,5 +8,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
index 3dfe3e5b381e3..1024caba971c7 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
@@ -29,5 +29,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
index 7ffee94d21260..f4e9603d9bd0e 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
@@ -29,5 +29,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
index ce04c675b7ae7..e2c333ffbc07a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
@@ -67,5 +67,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
index 01cbc41054308..8330210158484 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
@@ -29,5 +29,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
index b5640fd54e7b6..84d1dfc524a00 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
@@ -16,5 +16,6 @@
       "name": "libtest.so"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
index fc8c51a7aab2c..d3c64b8d3eaf3 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
@@ -8,5 +8,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
index 37ab9db4cb078..3297419191ef8 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
@@ -237,5 +237,6 @@
       "name": "test.cpp"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
index 6891a4cf9d2c7..c7493f7e44b63 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": ["invalid"],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
index d4e46c416adfb..e4f8167c42c68 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
@@ -10,5 +10,6 @@
       "summary_name": "PairsEntitySummary"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
index 666e612cb23e4..e2b47108e352c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
@@ -10,5 +10,6 @@
       "summary_data": []
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
index 59885a29bd4de..d386cc4d01feb 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": {},
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
index 16de981064a5f..a4d6723f0c595 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
@@ -39,5 +39,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
index 21c7437ab7767..16e47f09d2a00 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
@@ -30,5 +30,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
index 1af809fa8d3fc..c8051f1c65957 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
@@ -15,5 +15,6 @@
       "summary_data": []
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
index 41b1780868d2b..53ca9af49e1d2 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
@@ -11,5 +11,6 @@
       "summary_data": ["invalid"]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
index 1437b62764f11..5510ddccda80e 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
@@ -15,5 +15,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
index 5d3690a3c4d2d..add0a42a0efa6 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
@@ -15,5 +15,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
index 9f5e185269624..4d3b958f56b2c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
@@ -16,5 +16,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
index 5ce2a000ea4fc..a9b793c706697 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
@@ -18,5 +18,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
index 57692a0fb6499..d32cf5c7ff188 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
@@ -18,5 +18,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
index d3d657acc47d4..6a0f8b77c09e6 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
@@ -6,5 +6,6 @@
   "id_table": [123],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
index aede62a4f44d0..b08b426f3c411 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
@@ -14,5 +14,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
index 8bab17e3eb1ea..b6cdea259939a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
@@ -13,5 +13,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
index dcd650a4acd29..12b52496f3c04 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
@@ -15,5 +15,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
index 646d45ac19d79..098595093e1e0 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
@@ -6,5 +6,6 @@
   "id_table": {},
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
index a808fe0851126..a13fa2fe6bf42 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
index 79b507eac53bc..2e3cd065e82d9 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
@@ -23,5 +23,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
index 554c229a8aac6..b08e22e2bbd7e 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": ["invalid"],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
index 09ea51fd95c94..fde6f8b169cda 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
@@ -11,5 +11,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
index ff9e9a8796f2a..c9cabba10173e 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
@@ -11,5 +11,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
index 70c706f52c297..8fdc7c7bb18f0 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
@@ -11,5 +11,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
index 33a5478dba417..597db631bfd60 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
@@ -10,5 +10,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
index d29140c33c1cb..05654ecff98cd 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
@@ -10,5 +10,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
index cd37ea87aac40..e0d15d64a0d26 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
@@ -11,5 +11,6 @@
     }
   ],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
index bebf00b85fbf3..0ba968150772b 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
@@ -14,5 +14,6 @@
   ],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
index 33c339e625349..5823203d8a78a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": {},
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
index 90b75c77bfad9..acf745874f98c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
@@ -5,5 +5,6 @@
   },
   "id_table": [],
   "linkage_table": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
index 2918036a49ce6..32cd4e5fd8374 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
@@ -4,5 +4,6 @@
     "name": "test.cpp"
   },
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
index c34bb94d43068..5123eee3b4635 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
@@ -5,5 +5,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
index 657a3e0fb2e3b..d9a5e0c2c417f 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
@@ -5,5 +5,6 @@
   },
   "id_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
index 9b11f57bb6d6e..2bc2b044beb83 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
@@ -5,5 +5,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-target-triple.json
index 9c9fd1e54cd34..47f7230671601 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-target-triple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-target-triple.json
@@ -5,5 +5,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
index ed207878fae11..cf828c4303e30 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
@@ -2,5 +2,6 @@
   "target_triple": "arm64-apple-macosx",
   "id_table": [],
   "linkage_table": [],
-  "data": []
+  "data": [],
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-normalized-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-normalized-target-triple.json
index 5c860f82185d2..aa98ebf6db8ee 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-normalized-target-triple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-normalized-target-triple.json
@@ -6,5 +6,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
index 28a1283561741..7859843bdadb2 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
@@ -18,5 +18,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
index 8fbf45488e608..a5fdfb9159e59 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
@@ -23,5 +23,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
index 77d445a829efa..837478a480b03 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
@@ -18,5 +18,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
index e44ea77defc04..2b90c19e7329b 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
@@ -23,5 +23,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
index d2aaee379b58c..d9747413f533b 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
@@ -22,5 +22,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
index 6db5f643a5f8c..9032a351802bf 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
@@ -16,5 +16,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
index 0b07d911125ea..3c5df43fb79ba 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
@@ -22,5 +22,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
index 9d3d5d9ac8c41..a84b3a0c8cf19 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
@@ -16,5 +16,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
index 6a40e3ac9b073..2ba2b6956602f 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
@@ -11,5 +11,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
index 3e7b173c4d486..f89161ea705e7 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
@@ -6,5 +6,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
index 736e1c9649be9..d61e83b130a07 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
@@ -6,5 +6,6 @@
   "tu_namespace": {
     "kind": "LinkUnit",
     "name": "libtest.so"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
index 23432edfbaa59..bb26bc0de603a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
@@ -21,5 +21,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
index ee893d2aff65f..f3aa427a9e239 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
@@ -21,5 +21,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
index 21ba39a654782..c22c932ad2882 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
@@ -47,5 +47,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
index 8d3a5fc2ca76c..495890dc3cc44 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
@@ -21,5 +21,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
index 39c920a74f098..080afccbdf482 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
@@ -205,5 +205,6 @@
   "tu_namespace": {
     "kind": "CompilationUnit",
     "name": "test.cpp"
-  }
+  },
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-1.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-1.json
index 3b8a3c6fe9c78..0fe78af8c28bb 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-1.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-1.json
@@ -307,5 +307,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-2.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-2.json
index bc29dbc27177b..48a7fbef570e6 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-2.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-2.json
@@ -313,5 +313,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-empty.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-empty.json
index 7e6a69cd53d60..2b4e9179934d5 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-empty.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-empty.json
@@ -6,5 +6,6 @@
   "id_table": [],
   "linkage_table": [],
   "data": [],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-multikey.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-multikey.json
index 9e58c581216ec..a66be3036e31f 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-multikey.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-multikey.json
@@ -36,5 +36,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-ref.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-ref.json
index 1a0f27cf1f5ec..535cc18dc10d5 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-ref.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-ref.json
@@ -35,5 +35,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-value.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-value.json
index d28b819ec890f..1fd3d1aeb0ac9 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-value.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-invalid-entity-id-value.json
@@ -35,5 +35,6 @@
       ]
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-missing-fields.json b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-missing-fields.json
index fd3b7f27a806d..6d6daedb644b4 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-missing-fields.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Inputs/tu-missing-fields.json
@@ -3,5 +3,6 @@
     "kind": "CompilationUnit",
     "name": "missing-fields.cpp"
   },
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
index 648d7c361f01c..663f5dd814534 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
@@ -649,5 +649,6 @@
       "name": "lu-1+2"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
index a280ef079eb76..4fd99f978148b 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
@@ -361,5 +361,6 @@
       "name": "lu-1"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
index 7d9d67bc171ee..e7fd3f39da0c1 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
@@ -367,5 +367,6 @@
       "name": "lu-2"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-empty.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-empty.json
index 4c7f2ff646d14..30ba3ed8f0aed 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-empty.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-empty.json
@@ -8,5 +8,6 @@
       "name": "lu-empty"
     }
   ],
-  "target_triple": "arm64-apple-macosx"
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
 }

>From 5739e3cac02e15418abdcb47404ead3634240c30 Mon Sep 17 00:00:00 2001
From: Aviral Goel <goel.aviral at gmail.com>
Date: Wed, 17 Jun 2026 13:09:44 -0700
Subject: [PATCH 2/4] Add type field to TUSummary and LUSummary

---
 .../Core/Serialization/JSONFormat.h           |  29 ++
 .../Core/Serialization/SerializationFormat.h  |  36 +++
 .../Core/CMakeLists.txt                       |   1 +
 .../Serialization/JSONFormat/Artifact.cpp     | 161 +++++++++++
 .../JSONFormat/JSONFormatImpl.cpp             |  30 ++
 .../Serialization/JSONFormat/JSONFormatImpl.h |  32 +++
 .../Serialization/JSONFormat/LUSummary.cpp    |  30 +-
 .../JSONFormat/LUSummaryEncoding.cpp          |  30 +-
 .../Serialization/JSONFormat/TUSummary.cpp    |  30 +-
 .../JSONFormat/TUSummaryEncoding.cpp          |  30 +-
 .../LUSummary/Inputs/mismatched-type.json     |  13 +
 .../LUSummary/Inputs/missing-type.json        |  12 +
 .../ssaf-format/LUSummary/top-level.test      |  14 +
 .../TUSummary/Inputs/mismatched-type.json     |  11 +
 .../TUSummary/Inputs/missing-type.json        |  10 +
 .../ssaf-format/TUSummary/top-level.test      |  14 +
 .../CMakeLists.txt                            |   1 +
 .../TUSummaryExtractorFrontendActionTest.cpp  |  32 +++
 .../Registries/MockSerializationFormat.cpp    |  23 ++
 .../Registries/MockSerializationFormat.h      |  10 +
 .../JSONFormatTest/ArtifactTest.cpp           | 264 ++++++++++++++++++
 .../JSONFormatTest/LUSummaryTest.cpp          |   2 +
 .../JSONFormatTest/TUSummaryTest.cpp          |   2 +
 23 files changed, 773 insertions(+), 44 deletions(-)
 create mode 100644 clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/mismatched-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/mismatched-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-type.json
 create mode 100644 clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp

diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
index 9f538c373e491..c13f5299bbabc 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
@@ -52,6 +52,16 @@ class JSONFormat final : public SerializationFormat {
   llvm::Error writeLUSummary(const LUSummary &Summary,
                              llvm::StringRef Path) override;
 
+  llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) override;
+
+  llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path) override;
+
+  llvm::Expected<ArtifactEncoding>
+  readArtifactEncoding(llvm::StringRef Path) override;
+
+  llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
+                                    llvm::StringRef Path) override;
+
   llvm::Expected<LUSummaryEncoding>
   readLUSummaryEncoding(llvm::StringRef Path) override;
 
@@ -93,6 +103,25 @@ class JSONFormat final : public SerializationFormat {
   static std::map<SummaryName, FormatInfo> initFormatInfos();
   const std::map<SummaryName, FormatInfo> FormatInfos = initFormatInfos();
 
+  /// Parses a TUSummary from an already-validated root JSON object. The
+  /// caller is responsible for verifying the self-describing type field
+  /// and for wrapping any returned error with file-path context.
+  llvm::Expected<TUSummary> readTUSummaryFromObject(const Object &Root);
+
+  /// Parses an LUSummary from an already-validated root JSON object. See
+  /// \c readTUSummaryFromObject for caller responsibilities.
+  llvm::Expected<LUSummary> readLUSummaryFromObject(const Object &Root);
+
+  /// Parses a TUSummaryEncoding from an already-validated root JSON
+  /// object. See \c readTUSummaryFromObject for caller responsibilities.
+  llvm::Expected<TUSummaryEncoding>
+  readTUSummaryEncodingFromObject(const Object &Root);
+
+  /// Parses an LUSummaryEncoding from an already-validated root JSON
+  /// object. See \c readTUSummaryFromObject for caller responsibilities.
+  llvm::Expected<LUSummaryEncoding>
+  readLUSummaryEncodingFromObject(const Object &Root);
+
   EntityId entityIdFromJSON(const uint64_t EntityIdIndex) const;
   uint64_t entityIdToJSON(EntityId EI) const;
 
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index 080628a700ba1..d153dbfd8ef98 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -27,8 +27,21 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Registry.h"
 
+#include <variant>
+
 namespace clang::ssaf {
 
+/// Sum type returned by \c SerializationFormat::readArtifact, used when the
+/// caller does not know up-front which kind of top-level SSAF artifact a
+/// file contains. The active alternative is decided by the file's
+/// self-describing type field.
+using Artifact = std::variant<TUSummary, LUSummary>;
+
+/// Lazily-deserialized counterpart of \c Artifact: the same on-disk
+/// artifacts but with their per-entity summary payloads left as opaque
+/// format-specific encodings rather than fully resolved analysis results.
+using ArtifactEncoding = std::variant<TUSummaryEncoding, LUSummaryEncoding>;
+
 /// Abstract base class for serialization formats.
 class SerializationFormat {
 public:
@@ -51,6 +64,29 @@ class SerializationFormat {
   virtual llvm::Error writeLUSummary(const LUSummary &Summary,
                                      llvm::StringRef Path) = 0;
 
+  /// Generic read entry point. Inspects the file's self-describing type
+  /// field and dispatches to \c readTUSummary or \c readLUSummary
+  /// accordingly. Returns an error if the type field is missing or names
+  /// an unrecognized artifact kind.
+  virtual llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) = 0;
+
+  /// Generic write entry point. Dispatches to \c writeTUSummary or
+  /// \c writeLUSummary based on the active variant alternative.
+  virtual llvm::Error writeArtifact(const Artifact &A,
+                                    llvm::StringRef Path) = 0;
+
+  /// Encoding-flavored counterpart of \c readArtifact. Inspects the
+  /// self-describing type field and dispatches to
+  /// \c readTUSummaryEncoding or \c readLUSummaryEncoding accordingly.
+  virtual llvm::Expected<ArtifactEncoding>
+  readArtifactEncoding(llvm::StringRef Path) = 0;
+
+  /// Encoding-flavored counterpart of \c writeArtifact. Dispatches to
+  /// \c writeTUSummaryEncoding or \c writeLUSummaryEncoding based on the
+  /// active variant alternative.
+  virtual llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
+                                            llvm::StringRef Path) = 0;
+
   virtual llvm::Expected<LUSummaryEncoding>
   readLUSummaryEncoding(llvm::StringRef Path) = 0;
 
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Core/CMakeLists.txt
index 5085a9bc562e0..bcaf5db7f3093 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangScalableStaticAnalysisFrameworkCore
   Model/EntityLinkage.cpp
   Model/EntityName.cpp
   Model/SummaryName.cpp
+  Serialization/JSONFormat/Artifact.cpp
   Serialization/JSONFormat/JSONEntitySummaryEncoding.cpp
   Serialization/JSONFormat/JSONFormatImpl.cpp
   Serialization/JSONFormat/LUSummary.cpp
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
new file mode 100644
index 0000000000000..de2ea12e93d20
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
@@ -0,0 +1,161 @@
+//===- Artifact.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic artifact read/write entry points that dispatch on the
+// self-describing "type" field of the JSON document.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONFormatImpl.h"
+
+namespace clang::ssaf {
+
+llvm::Expected<Artifact> JSONFormat::readArtifact(llvm::StringRef Path) {
+  auto ExpectedJSON = readJSON(Path);
+  if (!ExpectedJSON) {
+    return ErrorBuilder::wrap(ExpectedJSON.takeError())
+        .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+        .build();
+  }
+
+  Object *RootObjectPtr = ExpectedJSON->getAsObject();
+  if (!RootObjectPtr) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObject, "Artifact",
+                                "object")
+        .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+        .build();
+  }
+
+  auto ExpectedType = readSummaryType(*RootObjectPtr);
+  if (!ExpectedType) {
+    return ErrorBuilder::wrap(ExpectedType.takeError())
+        .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+        .build();
+  }
+
+  // Dispatch by the self-describing type field. The helpers operate on
+  // the already-parsed root object so the file is read and parsed only
+  // once per readArtifact call.
+  if (*ExpectedType == JSONTypeValueTUSummary) {
+    auto ExpectedTU = readTUSummaryFromObject(*RootObjectPtr);
+    if (!ExpectedTU) {
+      return ErrorBuilder::wrap(ExpectedTU.takeError())
+          .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+          .build();
+    }
+    return Artifact{std::move(*ExpectedTU)};
+  }
+
+  if (*ExpectedType == JSONTypeValueLUSummary) {
+    auto ExpectedLU = readLUSummaryFromObject(*RootObjectPtr);
+    if (!ExpectedLU) {
+      return ErrorBuilder::wrap(ExpectedLU.takeError())
+          .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+          .build();
+    }
+    return Artifact{std::move(*ExpectedLU)};
+  }
+
+  return ErrorBuilder::create(std::errc::invalid_argument,
+                              ErrorMessages::UnknownSummaryType, *ExpectedType,
+                              JSONTypeKey, JSONTypeValueTUSummary,
+                              JSONTypeValueLUSummary)
+      .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+      .build();
+}
+
+llvm::Error JSONFormat::writeArtifact(const Artifact &A, llvm::StringRef Path) {
+  return std::visit(
+      [&](const auto &S) -> llvm::Error {
+        using T = std::decay_t<decltype(S)>;
+        if constexpr (std::is_same_v<T, TUSummary>) {
+          return writeTUSummary(S, Path);
+        } else {
+          static_assert(std::is_same_v<T, LUSummary>,
+                        "Artifact visitor must cover all variant alternatives");
+          return writeLUSummary(S, Path);
+        }
+      },
+      A);
+}
+
+llvm::Expected<ArtifactEncoding>
+JSONFormat::readArtifactEncoding(llvm::StringRef Path) {
+  auto ExpectedJSON = readJSON(Path);
+  if (!ExpectedJSON) {
+    return ErrorBuilder::wrap(ExpectedJSON.takeError())
+        .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+        .build();
+  }
+
+  Object *RootObjectPtr = ExpectedJSON->getAsObject();
+  if (!RootObjectPtr) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObject,
+                                "ArtifactEncoding", "object")
+        .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+        .build();
+  }
+
+  auto ExpectedType = readSummaryType(*RootObjectPtr);
+  if (!ExpectedType) {
+    return ErrorBuilder::wrap(ExpectedType.takeError())
+        .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+        .build();
+  }
+
+  // Dispatch by the self-describing type field. The helpers operate on
+  // the already-parsed root object so the file is read and parsed only
+  // once per readArtifactEncoding call.
+  if (*ExpectedType == JSONTypeValueTUSummary) {
+    auto ExpectedTU = readTUSummaryEncodingFromObject(*RootObjectPtr);
+    if (!ExpectedTU) {
+      return ErrorBuilder::wrap(ExpectedTU.takeError())
+          .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+          .build();
+    }
+    return ArtifactEncoding{std::move(*ExpectedTU)};
+  }
+
+  if (*ExpectedType == JSONTypeValueLUSummary) {
+    auto ExpectedLU = readLUSummaryEncodingFromObject(*RootObjectPtr);
+    if (!ExpectedLU) {
+      return ErrorBuilder::wrap(ExpectedLU.takeError())
+          .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+          .build();
+    }
+    return ArtifactEncoding{std::move(*ExpectedLU)};
+  }
+
+  return ErrorBuilder::create(std::errc::invalid_argument,
+                              ErrorMessages::UnknownSummaryType, *ExpectedType,
+                              JSONTypeKey, JSONTypeValueTUSummary,
+                              JSONTypeValueLUSummary)
+      .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
+      .build();
+}
+
+llvm::Error JSONFormat::writeArtifactEncoding(const ArtifactEncoding &E,
+                                              llvm::StringRef Path) {
+  return std::visit(
+      [&](const auto &Enc) -> llvm::Error {
+        using T = std::decay_t<decltype(Enc)>;
+        if constexpr (std::is_same_v<T, TUSummaryEncoding>) {
+          return writeTUSummaryEncoding(Enc, Path);
+        } else {
+          static_assert(
+              std::is_same_v<T, LUSummaryEncoding>,
+              "ArtifactEncoding visitor must cover all variant alternatives");
+          return writeLUSummaryEncoding(Enc, Path);
+        }
+      },
+      E);
+}
+
+} // namespace clang::ssaf
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.cpp
index 5bd37ad5113d5..f56e96295515d 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.cpp
@@ -147,6 +147,36 @@ SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr) {
 
 llvm::StringRef summaryNameToJSON(const SummaryName &SN) { return SN.str(); }
 
+//----------------------------------------------------------------------------
+// Summary Type field
+//----------------------------------------------------------------------------
+
+llvm::Expected<llvm::StringRef> readSummaryType(const Object &RootObject) {
+  std::optional<llvm::StringRef> OptType = RootObject.getString(JSONTypeKey);
+  if (!OptType) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "summary type", JSONTypeKey, "string")
+        .build();
+  }
+  return *OptType;
+}
+
+llvm::Error checkSummaryType(const Object &RootObject,
+                             llvm::StringRef ExpectedType) {
+  auto ExpectedActual = readSummaryType(RootObject);
+  if (!ExpectedActual) {
+    return ExpectedActual.takeError();
+  }
+  if (*ExpectedActual != ExpectedType) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::MismatchedSummaryType,
+                                ExpectedType, JSONTypeKey, *ExpectedActual)
+        .build();
+  }
+  return llvm::Error::success();
+}
+
 //----------------------------------------------------------------------------
 // AnalysisName
 //----------------------------------------------------------------------------
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
index 6903b7725c1b0..ca2274437470f 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
@@ -80,6 +80,11 @@ inline constexpr const char *FailedToReadObjectAtField =
 inline constexpr const char *FailedToReadObjectAtIndex =
     "failed to read {0} from index '{1}': expected JSON {2}";
 
+inline constexpr const char *MismatchedSummaryType =
+    "expected '{0}' for field '{1}' but got '{2}'";
+inline constexpr const char *UnknownSummaryType =
+    "unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'";
+
 inline constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo =
     "failed to deserialize EntitySummary: no FormatInfo registered for '{0}'";
 inline constexpr const char *FailedToSerializeEntitySummaryNoFormatInfo =
@@ -129,6 +134,33 @@ inline constexpr const char *TargetTripleNotNormalized =
 /// An entity ID is encoded as the single-key object {"@": <index>}.
 inline constexpr const char *JSONEntityIdKey = "@";
 
+//----------------------------------------------------------------------------
+// Summary Type JSON Representation
+//----------------------------------------------------------------------------
+
+/// Root-object key naming the summary kind so files are self-describing.
+inline constexpr const char *JSONTypeKey = "type";
+
+/// Value written to \c JSONTypeKey for serialized \c TUSummary files.
+inline constexpr const char *JSONTypeValueTUSummary = "TUSummary";
+
+/// Value written to \c JSONTypeKey for serialized \c LUSummary files.
+inline constexpr const char *JSONTypeValueLUSummary = "LUSummary";
+
+/// Value written to \c JSONTypeKey for serialized \c WPASuite files.
+inline constexpr const char *JSONTypeValueWPASuite = "WPASuite";
+
+/// Reads the \c JSONTypeKey field from the root object and verifies it
+/// equals \p ExpectedType. Returns success or an error with the field
+/// missing/mismatch detail.
+llvm::Error checkSummaryType(const Object &RootObject,
+                             llvm::StringRef ExpectedType);
+
+/// Reads the \c JSONTypeKey field from the root object as a string.
+/// Returns the string on success; on error, the message is suitable for
+/// callers that want to report the missing field themselves.
+llvm::Expected<llvm::StringRef> readSummaryType(const Object &RootObject);
+
 //----------------------------------------------------------------------------
 // JSON Reader and Writer
 //----------------------------------------------------------------------------
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummary.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummary.cpp
index 369334342790a..b0f7059b5fffc 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummary.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummary.cpp
@@ -36,14 +36,29 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
         .build();
   }
 
-  const Object &RootObject = *RootObjectPtr;
+  if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueLUSummary)) {
+    return ErrorBuilder::wrap(std::move(Err))
+        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
+        .build();
+  }
+
+  auto ExpectedSummary = readLUSummaryFromObject(*RootObjectPtr);
+  if (!ExpectedSummary) {
+    return ErrorBuilder::wrap(ExpectedSummary.takeError())
+        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
+        .build();
+  }
 
+  return std::move(*ExpectedSummary);
+}
+
+llvm::Expected<LUSummary>
+JSONFormat::readLUSummaryFromObject(const Object &RootObject) {
   auto OptTargetTriple = RootObject.getString("target_triple");
   if (!OptTargetTriple) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "TargetTriple", "target_triple", "string")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -51,7 +66,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
     return ErrorBuilder::wrap(std::move(Err))
         .context(ErrorMessages::ReadingFromField, "TargetTriple",
                  "target_triple")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -62,7 +76,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "NestedBuildNamespace", "lu_namespace", "array")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -71,7 +84,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
     return ErrorBuilder::wrap(ExpectedLUNamespace.takeError())
         .context(ErrorMessages::ReadingFromField, "NestedBuildNamespace",
                  "lu_namespace")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -83,7 +95,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "IdTable", "id_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -91,7 +102,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
     if (!ExpectedIdTable) {
       return ErrorBuilder::wrap(ExpectedIdTable.takeError())
           .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -104,7 +114,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "LinkageTable", "linkage_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -121,7 +130,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
           .context(ErrorMessages::ReadingFromField, "LinkageTable",
                    "linkage_table")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -134,7 +142,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "SummaryData entries", "data", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -144,7 +151,6 @@ llvm::Expected<LUSummary> JSONFormat::readLUSummary(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedSummaryDataMap.takeError())
           .context(ErrorMessages::ReadingFromField, "SummaryData entries",
                    "data")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -158,6 +164,8 @@ llvm::Error JSONFormat::writeLUSummary(const LUSummary &S,
                                        llvm::StringRef Path) {
   Object RootObject;
 
+  RootObject[JSONTypeKey] = JSONTypeValueLUSummary;
+
   RootObject["target_triple"] =
       llvm::Triple::normalize(getTargetTriple(S).str());
 
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp
index 9cd458e8ab09e..691f8cb5b7be1 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp
@@ -37,14 +37,29 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
         .build();
   }
 
-  const Object &RootObject = *RootObjectPtr;
+  if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueLUSummary)) {
+    return ErrorBuilder::wrap(std::move(Err))
+        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
+        .build();
+  }
+
+  auto ExpectedEncoding = readLUSummaryEncodingFromObject(*RootObjectPtr);
+  if (!ExpectedEncoding) {
+    return ErrorBuilder::wrap(ExpectedEncoding.takeError())
+        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
+        .build();
+  }
 
+  return std::move(*ExpectedEncoding);
+}
+
+llvm::Expected<LUSummaryEncoding>
+JSONFormat::readLUSummaryEncodingFromObject(const Object &RootObject) {
   auto OptTargetTriple = RootObject.getString("target_triple");
   if (!OptTargetTriple) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "TargetTriple", "target_triple", "string")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -52,7 +67,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::wrap(std::move(Err))
         .context(ErrorMessages::ReadingFromField, "TargetTriple",
                  "target_triple")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -63,7 +77,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "NestedBuildNamespace", "lu_namespace", "array")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -72,7 +85,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::wrap(ExpectedLUNamespace.takeError())
         .context(ErrorMessages::ReadingFromField, "NestedBuildNamespace",
                  "lu_namespace")
-        .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
         .build();
   }
 
@@ -84,7 +96,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "IdTable", "id_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -92,7 +103,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
     if (!ExpectedIdTable) {
       return ErrorBuilder::wrap(ExpectedIdTable.takeError())
           .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -105,7 +115,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "LinkageTable", "linkage_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -122,7 +131,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
           .context(ErrorMessages::ReadingFromField, "LinkageTable",
                    "linkage_table")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -135,7 +143,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "SummaryData entries", "data", "array")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -145,7 +152,6 @@ JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedEncodingSummaryDataMap.takeError())
           .context(ErrorMessages::ReadingFromField, "SummaryData entries",
                    "data")
-          .context(ErrorMessages::ReadingFromFile, "LUSummary", Path)
           .build();
     }
 
@@ -160,6 +166,8 @@ JSONFormat::writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
                                    llvm::StringRef Path) {
   Object RootObject;
 
+  RootObject[JSONTypeKey] = JSONTypeValueLUSummary;
+
   RootObject["target_triple"] =
       llvm::Triple::normalize(getTargetTriple(SummaryEncoding).str());
 
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummary.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummary.cpp
index 67b1dd4637689..1f543b9a60710 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummary.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummary.cpp
@@ -36,14 +36,29 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
         .build();
   }
 
-  const Object &RootObject = *RootObjectPtr;
+  if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueTUSummary)) {
+    return ErrorBuilder::wrap(std::move(Err))
+        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+        .build();
+  }
+
+  auto ExpectedSummary = readTUSummaryFromObject(*RootObjectPtr);
+  if (!ExpectedSummary) {
+    return ErrorBuilder::wrap(ExpectedSummary.takeError())
+        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+        .build();
+  }
 
+  return std::move(*ExpectedSummary);
+}
+
+llvm::Expected<TUSummary>
+JSONFormat::readTUSummaryFromObject(const Object &RootObject) {
   auto OptTargetTriple = RootObject.getString("target_triple");
   if (!OptTargetTriple) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "TargetTriple", "target_triple", "string")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -51,7 +66,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
     return ErrorBuilder::wrap(std::move(Err))
         .context(ErrorMessages::ReadingFromField, "TargetTriple",
                  "target_triple")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -62,7 +76,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "BuildNamespace", "tu_namespace", "object")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -71,7 +84,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
     return ErrorBuilder::wrap(ExpectedTUNamespace.takeError())
         .context(ErrorMessages::ReadingFromField, "BuildNamespace",
                  "tu_namespace")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -83,7 +95,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "IdTable", "id_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -91,7 +102,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
     if (!ExpectedIdTable) {
       return ErrorBuilder::wrap(ExpectedIdTable.takeError())
           .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -104,7 +114,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "LinkageTable", "linkage_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -121,7 +130,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
           .context(ErrorMessages::ReadingFromField, "LinkageTable",
                    "linkage_table")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -134,7 +142,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "SummaryData entries", "data", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -144,7 +151,6 @@ llvm::Expected<TUSummary> JSONFormat::readTUSummary(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedSummaryDataMap.takeError())
           .context(ErrorMessages::ReadingFromField, "SummaryData entries",
                    "data")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -158,6 +164,8 @@ llvm::Error JSONFormat::writeTUSummary(const TUSummary &S,
                                        llvm::StringRef Path) {
   Object RootObject;
 
+  RootObject[JSONTypeKey] = JSONTypeValueTUSummary;
+
   RootObject["target_triple"] =
       llvm::Triple::normalize(getTargetTriple(S).str());
 
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
index b4ebac02703ba..20167447e92d7 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/TUSummaryEncoding.cpp
@@ -37,14 +37,29 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
         .build();
   }
 
-  const Object &RootObject = *RootObjectPtr;
+  if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueTUSummary)) {
+    return ErrorBuilder::wrap(std::move(Err))
+        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+        .build();
+  }
+
+  auto ExpectedEncoding = readTUSummaryEncodingFromObject(*RootObjectPtr);
+  if (!ExpectedEncoding) {
+    return ErrorBuilder::wrap(ExpectedEncoding.takeError())
+        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+        .build();
+  }
 
+  return std::move(*ExpectedEncoding);
+}
+
+llvm::Expected<TUSummaryEncoding>
+JSONFormat::readTUSummaryEncodingFromObject(const Object &RootObject) {
   auto OptTargetTriple = RootObject.getString("target_triple");
   if (!OptTargetTriple) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "TargetTriple", "target_triple", "string")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -52,7 +67,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::wrap(std::move(Err))
         .context(ErrorMessages::ReadingFromField, "TargetTriple",
                  "target_triple")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -63,7 +77,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::create(std::errc::invalid_argument,
                                 ErrorMessages::FailedToReadObjectAtField,
                                 "BuildNamespace", "tu_namespace", "object")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -72,7 +85,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
     return ErrorBuilder::wrap(ExpectedTUNamespace.takeError())
         .context(ErrorMessages::ReadingFromField, "BuildNamespace",
                  "tu_namespace")
-        .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
         .build();
   }
 
@@ -84,7 +96,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "IdTable", "id_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -92,7 +103,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
     if (!ExpectedIdTable) {
       return ErrorBuilder::wrap(ExpectedIdTable.takeError())
           .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -105,7 +115,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "LinkageTable", "linkage_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -122,7 +131,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
           .context(ErrorMessages::ReadingFromField, "LinkageTable",
                    "linkage_table")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -135,7 +143,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "SummaryData entries", "data", "array")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -145,7 +152,6 @@ JSONFormat::readTUSummaryEncoding(llvm::StringRef Path) {
       return ErrorBuilder::wrap(ExpectedEncodingSummaryDataMap.takeError())
           .context(ErrorMessages::ReadingFromField, "SummaryData entries",
                    "data")
-          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
           .build();
     }
 
@@ -160,6 +166,8 @@ JSONFormat::writeTUSummaryEncoding(const TUSummaryEncoding &SummaryEncoding,
                                    llvm::StringRef Path) {
   Object RootObject;
 
+  RootObject[JSONTypeKey] = JSONTypeValueTUSummary;
+
   RootObject["target_triple"] =
       llvm::Triple::normalize(getTargetTriple(SummaryEncoding).str());
 
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/mismatched-type.json
new file mode 100644
index 0000000000000..fef18fcc1a874
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/mismatched-type.json
@@ -0,0 +1,13 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "target_triple": "arm64-apple-macosx",
+  "type": "TUSummary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-type.json
new file mode 100644
index 0000000000000..356001dbe68ae
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-type.json
@@ -0,0 +1,12 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "target_triple": "arm64-apple-macosx"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test
index da6087c0d6955..933a9227446a2 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test
@@ -97,3 +97,17 @@
 // NOT-NORMALIZED-TARGET-TRIPLE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}not-normalized-target-triple.json'
 // NOT-NORMALIZED-TARGET-TRIPLE-NEXT: reading TargetTriple from field 'target_triple'
 // NOT-NORMALIZED-TARGET-TRIPLE-NEXT: target triple 'arm64-macosx-apple' is not in normalized form (expected 'arm64-apple-macosx')
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// MISSING-TYPE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}missing-type.json'
+// MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/mismatched-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/mismatched-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// MISMATCHED-TYPE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}mismatched-type.json'
+// MISMATCHED-TYPE-NEXT: expected 'LUSummary' for field 'type' but got 'TUSummary'
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/mismatched-type.json
new file mode 100644
index 0000000000000..ff8de5a3b8d18
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/mismatched-type.json
@@ -0,0 +1,11 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "target_triple": "arm64-apple-macosx",
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "test.cpp"
+  },
+  "type": "LUSummary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-type.json
new file mode 100644
index 0000000000000..3e7b173c4d486
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-type.json
@@ -0,0 +1,10 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "target_triple": "arm64-apple-macosx",
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "test.cpp"
+  }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/top-level.test
index 48bdfe6376781..a17ddbb6e64e3 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/top-level.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/top-level.test
@@ -82,3 +82,17 @@
 // NOT-NORMALIZED-TARGET-TRIPLE:      clang-ssaf-format: error: reading TUSummary from file '{{.*}}not-normalized-target-triple.json'
 // NOT-NORMALIZED-TARGET-TRIPLE-NEXT: reading TargetTriple from field 'target_triple'
 // NOT-NORMALIZED-TARGET-TRIPLE-NEXT: target triple 'arm64-macosx-apple' is not in normalized form (expected 'arm64-apple-macosx')
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// MISSING-TYPE:      clang-ssaf-format: error: reading TUSummary from file '{{.*}}missing-type.json'
+// MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/mismatched-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/mismatched-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// MISMATCHED-TYPE:      clang-ssaf-format: error: reading TUSummary from file '{{.*}}mismatched-type.json'
+// MISMATCHED-TYPE-NEXT: expected 'TUSummary' for field 'type' but got 'LUSummary'
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
index 8d4a246ccbffb..8a371d5be875d 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
+++ b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
@@ -21,6 +21,7 @@ add_distinct_clang_unittest(ClangScalableAnalysisTests
   Registries/MockSummaryExtractor2.cpp
   Registries/SerializationFormatRegistryTest.cpp
   Registries/SummaryExtractorRegistryTest.cpp
+  Serialization/JSONFormatTest/ArtifactTest.cpp
   Serialization/JSONFormatTest/JSONFormatTest.cpp
   Serialization/JSONFormatTest/LUSummaryTest.cpp
   Serialization/JSONFormatTest/TUSummaryTest.cpp
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendActionTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendActionTest.cpp
index 18495cf876775..18d9e1735061d 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendActionTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendActionTest.cpp
@@ -106,6 +106,24 @@ class FailingSerializationFormat final : public SerializationFormat {
     return failing("writeWPASuite");
   }
 
+  llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) override {
+    return failing("readArtifact");
+  }
+
+  llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path) override {
+    return failing("writeArtifact");
+  }
+
+  llvm::Expected<ArtifactEncoding>
+  readArtifactEncoding(llvm::StringRef Path) override {
+    return failing("readArtifactEncoding");
+  }
+
+  llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
+                                    llvm::StringRef Path) override {
+    return failing("writeArtifactEncoding");
+  }
+
   void forEachRegisteredAnalysis(
       llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)>
           Callback) const override {}
@@ -166,6 +184,20 @@ class CapturingSerializationFormat final : public SerializationFormat {
   llvm::Error writeWPASuite(const WPASuite &, llvm::StringRef) override {
     return llvm::Error::success();
   }
+  llvm::Expected<Artifact> readArtifact(llvm::StringRef) override {
+    return llvm::createStringError("not implemented");
+  }
+  llvm::Error writeArtifact(const Artifact &, llvm::StringRef) override {
+    return llvm::Error::success();
+  }
+  llvm::Expected<ArtifactEncoding>
+  readArtifactEncoding(llvm::StringRef) override {
+    return llvm::createStringError("not implemented");
+  }
+  llvm::Error writeArtifactEncoding(const ArtifactEncoding &,
+                                    llvm::StringRef) override {
+    return llvm::Error::success();
+  }
   void forEachRegisteredAnalysis(
       llvm::function_ref<void(llvm::StringRef, llvm::StringRef)>)
       const override {}
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.cpp
index 549b6d0aeded3..03ed471f86087 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.cpp
@@ -207,3 +207,26 @@ llvm::Error MockSerializationFormat::writeWPASuite(const WPASuite &Suite,
                                                    llvm::StringRef Path) {
   llvm_unreachable("MockSerializationFormat does not support WPASuite");
 }
+
+llvm::Expected<Artifact>
+MockSerializationFormat::readArtifact(llvm::StringRef Path) {
+  llvm_unreachable("MockSerializationFormat does not support readArtifact");
+}
+
+llvm::Error MockSerializationFormat::writeArtifact(const Artifact &A,
+                                                   llvm::StringRef Path) {
+  llvm_unreachable("MockSerializationFormat does not support writeArtifact");
+}
+
+llvm::Expected<ArtifactEncoding>
+MockSerializationFormat::readArtifactEncoding(llvm::StringRef Path) {
+  llvm_unreachable(
+      "MockSerializationFormat does not support readArtifactEncoding");
+}
+
+llvm::Error
+MockSerializationFormat::writeArtifactEncoding(const ArtifactEncoding &E,
+                                               llvm::StringRef Path) {
+  llvm_unreachable(
+      "MockSerializationFormat does not support writeArtifactEncoding");
+}
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.h b/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.h
index b780d7a25953a..2f74f7216ba16 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.h
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Registries/MockSerializationFormat.h
@@ -44,6 +44,16 @@ class MockSerializationFormat final : public SerializationFormat {
   llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
                                      llvm::StringRef Path) override;
 
+  llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) override;
+
+  llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path) override;
+
+  llvm::Expected<ArtifactEncoding>
+  readArtifactEncoding(llvm::StringRef Path) override;
+
+  llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
+                                    llvm::StringRef Path) override;
+
   llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) override;
 
   llvm::Error writeWPASuite(const WPASuite &Suite,
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
new file mode 100644
index 0000000000000..6b36daf9abcf5
--- /dev/null
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
@@ -0,0 +1,264 @@
+//===- ArtifactTest.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for SerializationFormat::readArtifact / writeArtifact, the
+// generic dispatch entry points that switch on the JSON document's
+// self-describing "type" field.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONFormatTest.h"
+
+#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummary.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+
+#include <variant>
+
+using namespace clang::ssaf;
+using namespace llvm;
+using ::testing::AllOf;
+using ::testing::HasSubstr;
+
+namespace {
+
+class ArtifactTest : public JSONFormatTest {
+protected:
+  llvm::Expected<Artifact> readArtifactFromString(StringRef JSON) const {
+    auto ExpectedFilePath = writeJSON(JSON, "artifact.json");
+    if (!ExpectedFilePath) {
+      return ExpectedFilePath.takeError();
+    }
+    return JSONFormat().readArtifact(*ExpectedFilePath);
+  }
+
+  llvm::Error writeArtifact(const Artifact &A, StringRef FileName) {
+    PathString FilePath = makePath(FileName);
+    return JSONFormat().writeArtifact(A, FilePath);
+  }
+};
+
+TEST_F(ArtifactTest, ReadDispatchesToTUSummary) {
+  auto Result = readArtifactFromString(R"({
+    "type": "TUSummary",
+    "tu_namespace": {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    },
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  ASSERT_THAT_EXPECTED(Result, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<TUSummary>(*Result));
+}
+
+TEST_F(ArtifactTest, ReadDispatchesToLUSummary) {
+  auto Result = readArtifactFromString(R"({
+    "type": "LUSummary",
+    "lu_namespace": [
+      {
+        "kind": "LinkUnit",
+        "name": "test.exe"
+      }
+    ],
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  ASSERT_THAT_EXPECTED(Result, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<LUSummary>(*Result));
+}
+
+TEST_F(ArtifactTest, ReadMissingTypeField) {
+  auto Result = readArtifactFromString(R"({
+    "tu_namespace": {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    },
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading Artifact from file"),
+                  HasSubstr("failed to read summary type from field 'type'"))));
+}
+
+TEST_F(ArtifactTest, ReadUnknownTypeField) {
+  auto Result = readArtifactFromString(R"({
+    "type": "Mystery"
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading Artifact from file"),
+                  HasSubstr("unknown value 'Mystery' for field 'type'"))));
+}
+
+TEST_F(ArtifactTest, RoundTripTUSummary) {
+  TUSummary Summary(
+      llvm::Triple("arm64-apple-macosx"),
+      BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
+
+  Artifact A{std::move(Summary)};
+  auto WriteErr = writeArtifact(A, "tu-roundtrip.json");
+  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
+
+  PathString FilePath = makePath("tu-roundtrip.json");
+  auto ReadResult = JSONFormat().readArtifact(FilePath);
+  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<TUSummary>(*ReadResult));
+}
+
+TEST_F(ArtifactTest, RoundTripLUSummary) {
+  NestedBuildNamespace NBN(
+      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
+  LUSummary Summary(llvm::Triple("arm64-apple-macosx"), std::move(NBN));
+
+  Artifact A{std::move(Summary)};
+  auto WriteErr = writeArtifact(A, "lu-roundtrip.json");
+  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
+
+  PathString FilePath = makePath("lu-roundtrip.json");
+  auto ReadResult = JSONFormat().readArtifact(FilePath);
+  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<LUSummary>(*ReadResult));
+}
+
+// ============================================================================
+// ArtifactEncoding dispatch and round-trip tests
+// ============================================================================
+
+class ArtifactEncodingTest : public JSONFormatTest {
+protected:
+  llvm::Expected<ArtifactEncoding>
+  readArtifactEncodingFromString(StringRef JSON) const {
+    auto ExpectedFilePath = writeJSON(JSON, "encoding.json");
+    if (!ExpectedFilePath) {
+      return ExpectedFilePath.takeError();
+    }
+    return JSONFormat().readArtifactEncoding(*ExpectedFilePath);
+  }
+
+  llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
+                                    StringRef FileName) {
+    PathString FilePath = makePath(FileName);
+    return JSONFormat().writeArtifactEncoding(E, FilePath);
+  }
+};
+
+TEST_F(ArtifactEncodingTest, ReadDispatchesToTUSummaryEncoding) {
+  auto Result = readArtifactEncodingFromString(R"({
+    "type": "TUSummary",
+    "tu_namespace": {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    },
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  ASSERT_THAT_EXPECTED(Result, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<TUSummaryEncoding>(*Result));
+}
+
+TEST_F(ArtifactEncodingTest, ReadDispatchesToLUSummaryEncoding) {
+  auto Result = readArtifactEncodingFromString(R"({
+    "type": "LUSummary",
+    "lu_namespace": [
+      {
+        "kind": "LinkUnit",
+        "name": "test.exe"
+      }
+    ],
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  ASSERT_THAT_EXPECTED(Result, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<LUSummaryEncoding>(*Result));
+}
+
+TEST_F(ArtifactEncodingTest, ReadMissingTypeField) {
+  auto Result = readArtifactEncodingFromString(R"({
+    "tu_namespace": {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    },
+    "target_triple": "arm64-apple-macosx",
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading ArtifactEncoding from file"),
+                  HasSubstr("failed to read summary type from field 'type'"))));
+}
+
+TEST_F(ArtifactEncodingTest, ReadUnknownTypeField) {
+  auto Result = readArtifactEncodingFromString(R"({
+    "type": "Mystery"
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading ArtifactEncoding from file"),
+                  HasSubstr("unknown value 'Mystery' for field 'type'"))));
+}
+
+TEST_F(ArtifactEncodingTest, RoundTripTUSummaryEncoding) {
+  TUSummaryEncoding Encoding(
+      llvm::Triple("arm64-apple-macosx"),
+      BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
+
+  ArtifactEncoding E{std::move(Encoding)};
+  auto WriteErr = writeArtifactEncoding(E, "tu-enc-roundtrip.json");
+  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
+
+  PathString FilePath = makePath("tu-enc-roundtrip.json");
+  auto ReadResult = JSONFormat().readArtifactEncoding(FilePath);
+  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<TUSummaryEncoding>(*ReadResult));
+}
+
+TEST_F(ArtifactEncodingTest, RoundTripLUSummaryEncoding) {
+  NestedBuildNamespace NBN(
+      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
+  LUSummaryEncoding Encoding(llvm::Triple("arm64-apple-macosx"),
+                             std::move(NBN));
+
+  ArtifactEncoding E{std::move(Encoding)};
+  auto WriteErr = writeArtifactEncoding(E, "lu-enc-roundtrip.json");
+  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
+
+  PathString FilePath = makePath("lu-enc-roundtrip.json");
+  auto ReadResult = JSONFormat().readArtifactEncoding(FilePath);
+  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<LUSummaryEncoding>(*ReadResult));
+}
+
+} // anonymous namespace
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
index 76d6f4b01bca1..13e1b6c4d3f20 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
@@ -227,6 +227,7 @@ TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMissingData) {
       }
     ],
     "target_triple": "arm64-apple-macosx",
+    "type": "LUSummary",
     "id_table": [],
     "linkage_table": [],
     "data": [
@@ -264,6 +265,7 @@ TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
       }
     ],
     "target_triple": "arm64-apple-macosx",
+    "type": "LUSummary",
     "id_table": [],
     "linkage_table": [],
     "data": [
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
index d95a3e6d0015e..6e88013b2e4a6 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
@@ -220,6 +220,7 @@ TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryMissingData) {
       "name": "test.cpp"
     },
     "target_triple": "arm64-apple-macosx",
+    "type": "TUSummary",
     "id_table": [],
     "linkage_table": [],
     "data": [
@@ -255,6 +256,7 @@ TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
       "name": "test.cpp"
     },
     "target_triple": "arm64-apple-macosx",
+    "type": "TUSummary",
     "id_table": [],
     "linkage_table": [],
     "data": [

>From d8303d44099c792f7fa36d9d19c04511f2a3730f Mon Sep 17 00:00:00 2001
From: Aviral Goel <goel.aviral at gmail.com>
Date: Wed, 17 Jun 2026 13:32:45 -0700
Subject: [PATCH 3/4] Add type field to WPASuite and update clang-ssaf-format

---
 .../Core/Serialization/JSONFormat.h           |  4 +++
 .../Core/Serialization/SerializationFormat.h  |  2 +-
 .../Serialization/JSONFormat/Artifact.cpp     | 26 +++++++++++----
 .../Serialization/JSONFormat/JSONFormatImpl.h |  4 ++-
 .../Serialization/JSONFormat/WPASuite.cpp     | 24 +++++++++++---
 .../Inputs/wpa-result-bad-edges.json          |  3 +-
 .../PointerFlow/Inputs/wpa-result-bad-id.json |  3 +-
 .../PointerFlow/Inputs/wpa-result-empty.json  |  3 +-
 .../PointerFlow/Inputs/wpa-result-no-key.json |  3 +-
 .../Inputs/wpa-result-odd-count.json          |  3 +-
 .../PointerFlow/Inputs/wpa-result.json        |  3 +-
 .../Inputs/wpa-result-bad-epls.json           |  3 +-
 .../Inputs/wpa-result-bad-id.json             |  3 +-
 .../Inputs/wpa-result-empty.json              |  3 +-
 .../Inputs/wpa-result-no-key.json             |  3 +-
 .../Inputs/wpa-result-odd-count.json          |  3 +-
 .../UnsafeBufferUsage/Inputs/wpa-result.json  |  3 +-
 .../Scalable/ssaf-analyzer/Outputs/all.json   |  3 +-
 .../Scalable/ssaf-analyzer/Outputs/both.json  |  3 +-
 .../Scalable/ssaf-analyzer/Outputs/pairs.json |  3 +-
 .../Scalable/ssaf-analyzer/Outputs/tags.json  |  3 +-
 .../Inputs/duplicate-analysis-name.json       |  3 +-
 .../WPASuite/Inputs/mismatched-type.json      |  5 +++
 .../WPASuite/Inputs/missing-results.json      |  3 +-
 .../WPASuite/Inputs/missing-type.json         |  4 +++
 .../Inputs/pairs-result-bad-count.json        |  3 +-
 .../Inputs/pairs-result-bad-pair-counts.json  |  3 +-
 .../Inputs/pairs-result-entry-not-object.json |  3 +-
 .../pairs-result-missing-entity-id.json       |  3 +-
 ...result-entry-analysis-name-not-string.json |  3 +-
 .../result-entry-deserializer-error.json      |  3 +-
 .../result-entry-missing-analysis-name.json   |  3 +-
 .../result-entry-missing-result-field.json    |  3 +-
 .../Inputs/result-entry-no-format-info.json   |  3 +-
 .../Inputs/result-entry-not-object.json       |  3 +-
 .../result-entry-result-not-object.json       |  3 +-
 .../WPASuite/Inputs/results-not-array.json    |  3 +-
 .../WPASuite/Inputs/rt-all-results.json       |  3 +-
 .../ssaf-format/WPASuite/Inputs/rt-empty.json |  3 +-
 .../WPASuite/Inputs/rt-multiple-results.json  |  3 +-
 .../Inputs/tags-result-bad-element.json       |  3 +-
 .../Inputs/tags-result-missing-tags.json      |  3 +-
 .../tagspairs-result-bad-field-type.json      |  3 +-
 .../tagspairs-result-missing-field.json       |  3 +-
 .../ssaf-format/WPASuite/without-plugin.test  | 12 +++++++
 clang/tools/clang-ssaf-format/SSAFFormat.cpp  | 32 ++++++++++++-------
 .../JSONFormatTest/ArtifactTest.cpp           | 25 +++++++++++++++
 47 files changed, 186 insertions(+), 63 deletions(-)
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/mismatched-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-type.json

diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
index c13f5299bbabc..7841240319af6 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h
@@ -122,6 +122,10 @@ class JSONFormat final : public SerializationFormat {
   llvm::Expected<LUSummaryEncoding>
   readLUSummaryEncodingFromObject(const Object &Root);
 
+  /// Parses a WPASuite from an already-validated root JSON object. See
+  /// \c readTUSummaryFromObject for caller responsibilities.
+  llvm::Expected<WPASuite> readWPASuiteFromObject(const Object &Root);
+
   EntityId entityIdFromJSON(const uint64_t EntityIdIndex) const;
   uint64_t entityIdToJSON(EntityId EI) const;
 
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index d153dbfd8ef98..621182a352bc7 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -35,7 +35,7 @@ namespace clang::ssaf {
 /// caller does not know up-front which kind of top-level SSAF artifact a
 /// file contains. The active alternative is decided by the file's
 /// self-describing type field.
-using Artifact = std::variant<TUSummary, LUSummary>;
+using Artifact = std::variant<TUSummary, LUSummary, WPASuite>;
 
 /// Lazily-deserialized counterpart of \c Artifact: the same on-disk
 /// artifacts but with their per-entity summary payloads left as opaque
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
index de2ea12e93d20..424d7368cf33f 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/Artifact.cpp
@@ -62,10 +62,20 @@ llvm::Expected<Artifact> JSONFormat::readArtifact(llvm::StringRef Path) {
     return Artifact{std::move(*ExpectedLU)};
   }
 
+  if (*ExpectedType == JSONTypeValueWPASuite) {
+    auto ExpectedWPA = readWPASuiteFromObject(*RootObjectPtr);
+    if (!ExpectedWPA) {
+      return ErrorBuilder::wrap(ExpectedWPA.takeError())
+          .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
+          .build();
+    }
+    return Artifact{std::move(*ExpectedWPA)};
+  }
+
   return ErrorBuilder::create(std::errc::invalid_argument,
-                              ErrorMessages::UnknownSummaryType, *ExpectedType,
+                              ErrorMessages::UnknownArtifactType, *ExpectedType,
                               JSONTypeKey, JSONTypeValueTUSummary,
-                              JSONTypeValueLUSummary)
+                              JSONTypeValueLUSummary, JSONTypeValueWPASuite)
       .context(ErrorMessages::ReadingFromFile, "Artifact", Path)
       .build();
 }
@@ -76,10 +86,12 @@ llvm::Error JSONFormat::writeArtifact(const Artifact &A, llvm::StringRef Path) {
         using T = std::decay_t<decltype(S)>;
         if constexpr (std::is_same_v<T, TUSummary>) {
           return writeTUSummary(S, Path);
+        } else if constexpr (std::is_same_v<T, LUSummary>) {
+          return writeLUSummary(S, Path);
         } else {
-          static_assert(std::is_same_v<T, LUSummary>,
+          static_assert(std::is_same_v<T, WPASuite>,
                         "Artifact visitor must cover all variant alternatives");
-          return writeLUSummary(S, Path);
+          return writeWPASuite(S, Path);
         }
       },
       A);
@@ -134,9 +146,9 @@ JSONFormat::readArtifactEncoding(llvm::StringRef Path) {
   }
 
   return ErrorBuilder::create(std::errc::invalid_argument,
-                              ErrorMessages::UnknownSummaryType, *ExpectedType,
-                              JSONTypeKey, JSONTypeValueTUSummary,
-                              JSONTypeValueLUSummary)
+                              ErrorMessages::UnknownArtifactEncodingType,
+                              *ExpectedType, JSONTypeKey,
+                              JSONTypeValueTUSummary, JSONTypeValueLUSummary)
       .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path)
       .build();
 }
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
index ca2274437470f..d6ef9ab4b12f8 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
@@ -82,8 +82,10 @@ inline constexpr const char *FailedToReadObjectAtIndex =
 
 inline constexpr const char *MismatchedSummaryType =
     "expected '{0}' for field '{1}' but got '{2}'";
-inline constexpr const char *UnknownSummaryType =
+inline constexpr const char *UnknownArtifactType =
     "unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'";
+inline constexpr const char *UnknownArtifactEncodingType =
+    "unknown value '{0}' for field '{1}': expected '{2}' or '{3}'";
 
 inline constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo =
     "failed to deserialize EntitySummary: no FormatInfo registered for '{0}'";
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/WPASuite.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/WPASuite.cpp
index a37f8e838348e..e65a883279513 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/WPASuite.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/WPASuite.cpp
@@ -136,8 +136,24 @@ llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
         .build();
   }
 
-  const Object &RootObject = *RootObjectPtr;
+  if (auto Err = checkSummaryType(*RootObjectPtr, JSONTypeValueWPASuite)) {
+    return ErrorBuilder::wrap(std::move(Err))
+        .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
+        .build();
+  }
+
+  auto ExpectedSuite = readWPASuiteFromObject(*RootObjectPtr);
+  if (!ExpectedSuite) {
+    return ErrorBuilder::wrap(ExpectedSuite.takeError())
+        .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
+        .build();
+  }
 
+  return std::move(*ExpectedSuite);
+}
+
+llvm::Expected<WPASuite>
+JSONFormat::readWPASuiteFromObject(const Object &RootObject) {
   WPASuite Suite = makeWPASuite();
 
   {
@@ -146,7 +162,6 @@ llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "IdTable", "id_table", "array")
-          .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
           .build();
     }
 
@@ -154,7 +169,6 @@ llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
     if (!ExpectedIdTable) {
       return ErrorBuilder::wrap(ExpectedIdTable.takeError())
           .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
-          .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
           .build();
     }
 
@@ -167,7 +181,6 @@ llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
       return ErrorBuilder::create(std::errc::invalid_argument,
                                   ErrorMessages::FailedToReadObjectAtField,
                                   "WPA results", "results", "array")
-          .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
           .build();
     }
 
@@ -175,7 +188,6 @@ llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
     if (!ExpectedResultsMap) {
       return ErrorBuilder::wrap(ExpectedResultsMap.takeError())
           .context(ErrorMessages::ReadingFromField, "WPA results", "results")
-          .context(ErrorMessages::ReadingFromFile, "WPASuite", Path)
           .build();
     }
 
@@ -189,6 +201,8 @@ llvm::Error JSONFormat::writeWPASuite(const WPASuite &Suite,
                                       llvm::StringRef Path) {
   Object RootObject;
 
+  RootObject[JSONTypeKey] = JSONTypeValueWPASuite;
+
   RootObject["id_table"] = luEntityIdTableToJSON(getIdTable(Suite));
 
   auto ExpectedResults = analysisResultMapToJSON(getData(Suite));
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-edges.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-edges.json
index cd9084d5a69bd..85d68e0b5f1d0 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-edges.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-edges.json
@@ -26,5 +26,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-id.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-id.json
index 08102111e224d..7b2677b003454 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-id.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-bad-id.json
@@ -10,5 +10,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-empty.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-empty.json
index 2eed81bc8e990..274ecdbbc5c4c 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-empty.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-empty.json
@@ -7,5 +7,6 @@
         "PointerFlowAnalysisResult": []
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-no-key.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-no-key.json
index 32bda55463253..5a16915b79546 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-no-key.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-no-key.json
@@ -7,5 +7,6 @@
         "WrongKey": []
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-odd-count.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-odd-count.json
index 32c36f549509a..391926df77dcb 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-odd-count.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result-odd-count.json
@@ -25,5 +25,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result.json b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result.json
index bd5b215d9ad9a..2d28f8697d339 100644
--- a/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result.json
+++ b/clang/test/Analysis/Scalable/PointerFlow/Inputs/wpa-result.json
@@ -124,5 +124,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-epls.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-epls.json
index 9f2be6121ff05..f7ee6a2d197e8 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-epls.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-epls.json
@@ -26,5 +26,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-id.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-id.json
index 58f1fabc2d16a..57f92bbe14ff9 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-id.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-bad-id.json
@@ -10,5 +10,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-empty.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-empty.json
index 89a58332cfd17..773f938de0bdf 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-empty.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-empty.json
@@ -7,5 +7,6 @@
         "UnsafeBufferUsageAnalysisResult": []
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-no-key.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-no-key.json
index 7d68ef8998871..d97f1a23faf72 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-no-key.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-no-key.json
@@ -7,5 +7,6 @@
         "WrongKey": []
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-odd-count.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-odd-count.json
index 12725357b5a30..005a51a849f8f 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-odd-count.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result-odd-count.json
@@ -25,5 +25,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result.json
index a5b8c1cc9df7b..b3d2d605b7946 100644
--- a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result.json
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/wpa-result.json
@@ -82,5 +82,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json
index d408b64d05af3..f1e8cf98553c9 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json
@@ -86,5 +86,6 @@
         "unique_tag_count": 4
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json
index e5f7170814295..814fea5823441 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json
@@ -77,5 +77,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json
index 3f52b0acfd900..c8431c7280ce0 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json
@@ -66,5 +66,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json
index aa41194746ea9..c3a7cfe9d6edb 100644
--- a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json
+++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json
@@ -52,5 +52,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/duplicate-analysis-name.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/duplicate-analysis-name.json
index fd74c67652c8a..847026b5b4b9c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/duplicate-analysis-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/duplicate-analysis-name.json
@@ -13,5 +13,6 @@
         "tags": []
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/mismatched-type.json
new file mode 100644
index 0000000000000..e29ea03a5507b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/mismatched-type.json
@@ -0,0 +1,5 @@
+{
+  "id_table": [],
+  "results": [],
+  "type": "TUSummary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-results.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-results.json
index ff4d6243d5440..f694a4b710997 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-results.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-results.json
@@ -1,3 +1,4 @@
 {
-  "id_table": []
+  "id_table": [],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-type.json
new file mode 100644
index 0000000000000..80637e10fc66f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/missing-type.json
@@ -0,0 +1,4 @@
+{
+  "id_table": [],
+  "results": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-count.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-count.json
index 696455956c61b..4cc1f4f3522ee 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-count.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-count.json
@@ -53,5 +53,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-pair-counts.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-pair-counts.json
index b1a22a22719b7..12560227ac769 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-pair-counts.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-bad-pair-counts.json
@@ -13,5 +13,6 @@
         "pair_counts": "not-an-array"
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-entry-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-entry-not-object.json
index 7214de7472a6d..3be3acba1aa77 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-entry-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-entry-not-object.json
@@ -29,5 +29,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-missing-entity-id.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-missing-entity-id.json
index 7fc060468c79f..8eb3954a342e9 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-missing-entity-id.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/pairs-result-missing-entity-id.json
@@ -37,5 +37,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-analysis-name-not-string.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-analysis-name-not-string.json
index 785cff5958593..815f8679e80b9 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-analysis-name-not-string.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-analysis-name-not-string.json
@@ -5,5 +5,6 @@
       "analysis_name": 42,
       "result": {}
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-deserializer-error.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-deserializer-error.json
index 2cae1712c4022..3f93bb2132b40 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-deserializer-error.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-deserializer-error.json
@@ -22,5 +22,6 @@
         "tags": "not-an-array"
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-analysis-name.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-analysis-name.json
index f65513df39bc4..89347b0ac4afc 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-analysis-name.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-analysis-name.json
@@ -4,5 +4,6 @@
     {
       "result": {}
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-result-field.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-result-field.json
index 134b03ac9e551..317d0cdd356c3 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-result-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-missing-result-field.json
@@ -12,5 +12,6 @@
     {
       "analysis_name": "PairsAnalysisResult"
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-no-format-info.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-no-format-info.json
index 49dad19a78281..0bd79ba092851 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-no-format-info.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-no-format-info.json
@@ -5,5 +5,6 @@
       "analysis_name": "UnregisteredAnalysis",
       "result": {}
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-not-object.json
index d95d3a942f667..3ca316565629c 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-not-object.json
@@ -2,5 +2,6 @@
   "id_table": [],
   "results": [
     "invalid"
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-result-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-result-not-object.json
index bfe76634fd94a..3bcf37413f126 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-result-not-object.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/result-entry-result-not-object.json
@@ -22,5 +22,6 @@
       "analysis_name": "PairsAnalysisResult",
       "result": "not_an_object"
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/results-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/results-not-array.json
index 4b88b7ac4138c..a7e0fd67832e2 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/results-not-array.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/results-not-array.json
@@ -1,4 +1,5 @@
 {
   "id_table": [],
-  "results": {}
+  "results": {},
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-all-results.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-all-results.json
index 8bd6679b4a06e..5b50a4da1dc98 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-all-results.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-all-results.json
@@ -86,5 +86,6 @@
         "unique_tag_count": 4
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-empty.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-empty.json
index 80637e10fc66f..c9a2c4421b807 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-empty.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-empty.json
@@ -1,4 +1,5 @@
 {
   "id_table": [],
-  "results": []
+  "results": [],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-multiple-results.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-multiple-results.json
index 70fc8a955cc50..e07b8abf9e712 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-multiple-results.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/rt-multiple-results.json
@@ -36,5 +36,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-bad-element.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-bad-element.json
index 267f79b1caed0..f03765aab3bfe 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-bad-element.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-bad-element.json
@@ -11,5 +11,6 @@
         ]
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-missing-tags.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-missing-tags.json
index a92d812518cd2..f5367b94bc168 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-missing-tags.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tags-result-missing-tags.json
@@ -11,5 +11,6 @@
       "analysis_name": "TagsAnalysisResult",
       "result": {}
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-bad-field-type.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-bad-field-type.json
index ad489ffae4987..bf488a3eb64b5 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-bad-field-type.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-bad-field-type.json
@@ -16,5 +16,6 @@
         "unique_tag_count": "not-a-number"
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-missing-field.json b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-missing-field.json
index 100ddccc4e37f..c2491ff6b8d27 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-missing-field.json
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/Inputs/tagspairs-result-missing-field.json
@@ -21,5 +21,6 @@
         "unique_tag_count": 1
       }
     }
-  ]
+  ],
+  "type": "WPASuite"
 }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/without-plugin.test b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/without-plugin.test
index afe16aa6643a2..8c07dd437cb79 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/WPASuite/without-plugin.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/WPASuite/without-plugin.test
@@ -13,6 +13,18 @@
 // NO-RESULTS:      clang-ssaf-format: error: reading WPASuite from file '{{.*}}missing-results.json'
 // NO-RESULTS-NEXT: failed to read WPA results from field 'results': expected JSON array
 
+// 'type' field is absent.
+// RUN: not clang-ssaf-format --type wpa %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE
+// MISSING-TYPE:      clang-ssaf-format: error: reading WPASuite from file '{{.*}}missing-type.json'
+// MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// 'type' field names a different artifact kind.
+// RUN: not clang-ssaf-format --type wpa %S/Inputs/mismatched-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE
+// MISMATCHED-TYPE:      clang-ssaf-format: error: reading WPASuite from file '{{.*}}mismatched-type.json'
+// MISMATCHED-TYPE-NEXT: expected 'WPASuite' for field 'type' but got 'TUSummary'
+
 // 'results' is an object, not an array.
 // RUN: not clang-ssaf-format --type wpa %S/Inputs/results-not-array.json 2>&1 \
 // RUN:   | FileCheck %s --match-full-lines --check-prefix=RESULTS-OBJ
diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
index c076c94e748a6..c1762c0fa3297 100644
--- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp
+++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
@@ -39,7 +39,7 @@ namespace {
 // Summary Type
 //===----------------------------------------------------------------------===//
 
-enum class SummaryType { TU, LU, WPA };
+enum class SummaryType { Auto, TU, LU, WPA };
 
 //===----------------------------------------------------------------------===//
 // Command-Line Options
@@ -52,15 +52,20 @@ cl::list<std::string> LoadPlugins("load",
                                   cl::value_desc("path"),
                                   cl::cat(SsafFormatCategory));
 
-// --type and the input file are required for convert/validateInput operations
-// but must be optional at the cl layer so that --list can be used standalone.
+// Defaults to 'auto', which inspects the file's self-describing 'type'
+// field and dispatches to the matching reader/writer. Explicit values
+// force the use of the corresponding kind-specific reader/writer.
 cl::opt<SummaryType> Type(
-    "type", cl::desc("Summary type (required unless --list is given)"),
-    cl::values(clEnumValN(SummaryType::TU, "tu", "Translation unit summary"),
+    "type",
+    cl::desc("Summary type (defaults to 'auto', which uses the file's "
+             "self-describing 'type' field)"),
+    cl::values(clEnumValN(SummaryType::Auto, "auto",
+                          "Detect type from the file's 'type' field"),
+               clEnumValN(SummaryType::TU, "tu", "Translation unit summary"),
                clEnumValN(SummaryType::LU, "lu", "Link unit summary"),
                clEnumValN(SummaryType::WPA, "wpa",
                           "Whole-program analysis suite")),
-    cl::cat(SsafFormatCategory));
+    cl::init(SummaryType::Auto), cl::cat(SsafFormatCategory));
 
 cl::opt<std::string> InputPath(cl::Positional, cl::desc("<input file>"),
                                cl::cat(SsafFormatCategory));
@@ -222,12 +227,6 @@ FormatInput validateInput() {
 
   FormatInput FI;
 
-  // Validate Type explicitly since we don't want to specify it if --list is
-  // provided.
-  if (!Type.getNumOccurrences()) {
-    fail("'--type' option is required");
-  }
-
   // Validate the input path.
   {
     if (InputPath.empty()) {
@@ -269,6 +268,15 @@ void run(const FormatInput &FI, ReadFn Read, WriteFn Write) {
 
 void convert(const FormatInput &FI) {
   switch (Type) {
+  case SummaryType::Auto:
+    if (UseEncoding) {
+      run(FI, &SerializationFormat::readArtifactEncoding,
+          &SerializationFormat::writeArtifactEncoding);
+    } else {
+      run(FI, &SerializationFormat::readArtifact,
+          &SerializationFormat::writeArtifact);
+    }
+    return;
   case SummaryType::TU:
     if (UseEncoding) {
       run(FI, &SerializationFormat::readTUSummaryEncoding,
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
index 6b36daf9abcf5..ed720c5a5ab32 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
@@ -20,6 +20,7 @@
 #include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/WPASuite.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gmock/gmock.h"
 
@@ -84,6 +85,17 @@ TEST_F(ArtifactTest, ReadDispatchesToLUSummary) {
   EXPECT_TRUE(std::holds_alternative<LUSummary>(*Result));
 }
 
+TEST_F(ArtifactTest, ReadDispatchesToWPASuite) {
+  auto Result = readArtifactFromString(R"({
+    "type": "WPASuite",
+    "id_table": [],
+    "results": []
+  })");
+
+  ASSERT_THAT_EXPECTED(Result, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<WPASuite>(*Result));
+}
+
 TEST_F(ArtifactTest, ReadMissingTypeField) {
   auto Result = readArtifactFromString(R"({
     "tu_namespace": {
@@ -143,6 +155,19 @@ TEST_F(ArtifactTest, RoundTripLUSummary) {
   EXPECT_TRUE(std::holds_alternative<LUSummary>(*ReadResult));
 }
 
+TEST_F(ArtifactTest, RoundTripWPASuite) {
+  WPASuite Suite = makeWPASuite();
+
+  Artifact A{std::move(Suite)};
+  auto WriteErr = writeArtifact(A, "wpa-roundtrip.json");
+  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
+
+  PathString FilePath = makePath("wpa-roundtrip.json");
+  auto ReadResult = JSONFormat().readArtifact(FilePath);
+  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
+  EXPECT_TRUE(std::holds_alternative<WPASuite>(*ReadResult));
+}
+
 // ============================================================================
 // ArtifactEncoding dispatch and round-trip tests
 // ============================================================================

>From 406060858f741f5806a80fe9980247100d3e699e Mon Sep 17 00:00:00 2001
From: Aviral Goel <goel.aviral at gmail.com>
Date: Wed, 17 Jun 2026 13:54:09 -0700
Subject: [PATCH 4/4] Remove ArtifactTest

---
 .../Serialization/JSONFormat/JSONFormatImpl.h |   2 +-
 .../Artifact/Inputs/missing-type.json         |   2 +
 .../Artifact/Inputs/rt-lu-empty.json          |  13 +
 .../Artifact/Inputs/rt-tu-empty.json          |  11 +
 .../Artifact/Inputs/rt-wpa-empty.json         |   5 +
 .../Artifact/Inputs/unknown-type.json         |   3 +
 .../ssaf-format/Artifact/round-trip.test      |  40 +++
 .../ssaf-format/Artifact/top-level.test       |  43 +++
 .../CMakeLists.txt                            |   1 -
 .../JSONFormatTest/ArtifactTest.cpp           | 289 ------------------
 10 files changed, 118 insertions(+), 291 deletions(-)
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/missing-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-lu-empty.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-tu-empty.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-wpa-empty.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/unknown-type.json
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
 create mode 100644 clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
 delete mode 100644 clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp

diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
index d6ef9ab4b12f8..44eb62fba6024 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat/JSONFormatImpl.h
@@ -85,7 +85,7 @@ inline constexpr const char *MismatchedSummaryType =
 inline constexpr const char *UnknownArtifactType =
     "unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'";
 inline constexpr const char *UnknownArtifactEncodingType =
-    "unknown value '{0}' for field '{1}': expected '{2}' or '{3}'";
+    "unknown value '{0}' for field '{1}': expected '{2}', or '{3}'";
 
 inline constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo =
     "failed to deserialize EntitySummary: no FormatInfo registered for '{0}'";
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/missing-type.json
new file mode 100644
index 0000000000000..2c63c0851048d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/missing-type.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-lu-empty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-lu-empty.json
new file mode 100644
index 0000000000000..d3c64b8d3eaf3
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-lu-empty.json
@@ -0,0 +1,13 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ],
+  "target_triple": "arm64-apple-macosx",
+  "type": "LUSummary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-tu-empty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-tu-empty.json
new file mode 100644
index 0000000000000..f89161ea705e7
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-tu-empty.json
@@ -0,0 +1,11 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "target_triple": "arm64-apple-macosx",
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "test.cpp"
+  },
+  "type": "TUSummary"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-wpa-empty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-wpa-empty.json
new file mode 100644
index 0000000000000..c9a2c4421b807
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-wpa-empty.json
@@ -0,0 +1,5 @@
+{
+  "id_table": [],
+  "results": [],
+  "type": "WPASuite"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/unknown-type.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/unknown-type.json
new file mode 100644
index 0000000000000..49b663b0a32dd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/unknown-type.json
@@ -0,0 +1,3 @@
+{
+  "type": "Mystery"
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
new file mode 100644
index 0000000000000..4ddb233940afe
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test
@@ -0,0 +1,40 @@
+// Round-trip tests for clang-ssaf-format auto mode (no --type, or explicit
+// --type auto, dispatch by the self-describing 'type' field). Reads each
+// fixture, writes it back via the matching reader/writer pair selected from
+// the variant, and diffs the result against the original.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// Artifact round-trips (resolved)
+// ============================================================================
+
+// RUN: clang-ssaf-format %S/Inputs/rt-tu-empty.json -o %t/rt-tu-empty.json
+// RUN: diff %S/Inputs/rt-tu-empty.json %t/rt-tu-empty.json
+// RUN: clang-ssaf-format --type auto %S/Inputs/rt-tu-empty.json -o %t/rt-tu-empty-explicit.json
+// RUN: diff %S/Inputs/rt-tu-empty.json %t/rt-tu-empty-explicit.json
+
+// RUN: clang-ssaf-format %S/Inputs/rt-lu-empty.json -o %t/rt-lu-empty.json
+// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty.json
+// RUN: clang-ssaf-format --type auto %S/Inputs/rt-lu-empty.json -o %t/rt-lu-empty-explicit.json
+// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty-explicit.json
+
+// RUN: clang-ssaf-format %S/Inputs/rt-wpa-empty.json -o %t/rt-wpa-empty.json
+// RUN: diff %S/Inputs/rt-wpa-empty.json %t/rt-wpa-empty.json
+// RUN: clang-ssaf-format --type auto %S/Inputs/rt-wpa-empty.json -o %t/rt-wpa-empty-explicit.json
+// RUN: diff %S/Inputs/rt-wpa-empty.json %t/rt-wpa-empty-explicit.json
+
+// ============================================================================
+// ArtifactEncoding round-trips (--encoding)
+// ============================================================================
+
+// RUN: clang-ssaf-format --encoding %S/Inputs/rt-tu-empty.json -o %t/rt-tu-empty-enc.json
+// RUN: diff %S/Inputs/rt-tu-empty.json %t/rt-tu-empty-enc.json
+// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-tu-empty.json -o %t/rt-tu-empty-enc-explicit.json
+// RUN: diff %S/Inputs/rt-tu-empty.json %t/rt-tu-empty-enc-explicit.json
+
+// RUN: clang-ssaf-format --encoding %S/Inputs/rt-lu-empty.json -o %t/rt-lu-empty-enc.json
+// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty-enc.json
+// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-lu-empty.json -o %t/rt-lu-empty-enc-explicit.json
+// RUN: diff %S/Inputs/rt-lu-empty.json %t/rt-lu-empty-enc-explicit.json
diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
new file mode 100644
index 0000000000000..904b1dffa7d7b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test
@@ -0,0 +1,43 @@
+// Top-level Artifact tests for clang-ssaf-format auto mode (no --type, or
+// explicit --type auto, dispatch by the self-describing 'type' field).
+// Covers both the resolved Artifact path and the ArtifactEncoding path.
+
+// ============================================================================
+// readArtifact errors (no --type, no --encoding)
+// ============================================================================
+
+// 'type' field is absent.
+// RUN: not clang-ssaf-format %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ARTIFACT-MISSING-TYPE
+// RUN: not clang-ssaf-format --type auto %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ARTIFACT-MISSING-TYPE
+// ARTIFACT-MISSING-TYPE:      clang-ssaf-format: error: reading Artifact from file '{{.*}}missing-type.json'
+// ARTIFACT-MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// 'type' field names an unrecognized artifact kind.
+// RUN: not clang-ssaf-format %S/Inputs/unknown-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ARTIFACT-UNKNOWN-TYPE
+// RUN: not clang-ssaf-format --type auto %S/Inputs/unknown-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ARTIFACT-UNKNOWN-TYPE
+// ARTIFACT-UNKNOWN-TYPE:      clang-ssaf-format: error: reading Artifact from file '{{.*}}unknown-type.json'
+// ARTIFACT-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', 'LUSummary', or 'WPASuite'
+
+// ============================================================================
+// readArtifactEncoding errors (no --type, --encoding)
+// ============================================================================
+
+// 'type' field is absent.
+// RUN: not clang-ssaf-format --encoding %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENCODING-MISSING-TYPE
+// RUN: not clang-ssaf-format --type auto --encoding %S/Inputs/missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENCODING-MISSING-TYPE
+// ENCODING-MISSING-TYPE:      clang-ssaf-format: error: reading ArtifactEncoding from file '{{.*}}missing-type.json'
+// ENCODING-MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string
+
+// 'type' field names an unrecognized artifact kind.
+// RUN: not clang-ssaf-format --encoding %S/Inputs/unknown-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENCODING-UNKNOWN-TYPE
+// RUN: not clang-ssaf-format --type auto --encoding %S/Inputs/unknown-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENCODING-UNKNOWN-TYPE
+// ENCODING-UNKNOWN-TYPE:      clang-ssaf-format: error: reading ArtifactEncoding from file '{{.*}}unknown-type.json'
+// ENCODING-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', or 'LUSummary'
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
index 8a371d5be875d..8d4a246ccbffb 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
+++ b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt
@@ -21,7 +21,6 @@ add_distinct_clang_unittest(ClangScalableAnalysisTests
   Registries/MockSummaryExtractor2.cpp
   Registries/SerializationFormatRegistryTest.cpp
   Registries/SummaryExtractorRegistryTest.cpp
-  Serialization/JSONFormatTest/ArtifactTest.cpp
   Serialization/JSONFormatTest/JSONFormatTest.cpp
   Serialization/JSONFormatTest/LUSummaryTest.cpp
   Serialization/JSONFormatTest/TUSummaryTest.cpp
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
deleted file mode 100644
index ed720c5a5ab32..0000000000000
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/ArtifactTest.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-//===- ArtifactTest.cpp ---------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Unit tests for SerializationFormat::readArtifact / writeArtifact, the
-// generic dispatch entry points that switch on the JSON document's
-// self-describing "type" field.
-//
-//===----------------------------------------------------------------------===//
-
-#include "JSONFormatTest.h"
-
-#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummary.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummaryEncoding.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/WPASuite.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-
-#include <variant>
-
-using namespace clang::ssaf;
-using namespace llvm;
-using ::testing::AllOf;
-using ::testing::HasSubstr;
-
-namespace {
-
-class ArtifactTest : public JSONFormatTest {
-protected:
-  llvm::Expected<Artifact> readArtifactFromString(StringRef JSON) const {
-    auto ExpectedFilePath = writeJSON(JSON, "artifact.json");
-    if (!ExpectedFilePath) {
-      return ExpectedFilePath.takeError();
-    }
-    return JSONFormat().readArtifact(*ExpectedFilePath);
-  }
-
-  llvm::Error writeArtifact(const Artifact &A, StringRef FileName) {
-    PathString FilePath = makePath(FileName);
-    return JSONFormat().writeArtifact(A, FilePath);
-  }
-};
-
-TEST_F(ArtifactTest, ReadDispatchesToTUSummary) {
-  auto Result = readArtifactFromString(R"({
-    "type": "TUSummary",
-    "tu_namespace": {
-      "kind": "CompilationUnit",
-      "name": "test.cpp"
-    },
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  ASSERT_THAT_EXPECTED(Result, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<TUSummary>(*Result));
-}
-
-TEST_F(ArtifactTest, ReadDispatchesToLUSummary) {
-  auto Result = readArtifactFromString(R"({
-    "type": "LUSummary",
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  ASSERT_THAT_EXPECTED(Result, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<LUSummary>(*Result));
-}
-
-TEST_F(ArtifactTest, ReadDispatchesToWPASuite) {
-  auto Result = readArtifactFromString(R"({
-    "type": "WPASuite",
-    "id_table": [],
-    "results": []
-  })");
-
-  ASSERT_THAT_EXPECTED(Result, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<WPASuite>(*Result));
-}
-
-TEST_F(ArtifactTest, ReadMissingTypeField) {
-  auto Result = readArtifactFromString(R"({
-    "tu_namespace": {
-      "kind": "CompilationUnit",
-      "name": "test.cpp"
-    },
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  EXPECT_THAT_EXPECTED(
-      Result, FailedWithMessage(AllOf(
-                  HasSubstr("reading Artifact from file"),
-                  HasSubstr("failed to read summary type from field 'type'"))));
-}
-
-TEST_F(ArtifactTest, ReadUnknownTypeField) {
-  auto Result = readArtifactFromString(R"({
-    "type": "Mystery"
-  })");
-
-  EXPECT_THAT_EXPECTED(
-      Result, FailedWithMessage(AllOf(
-                  HasSubstr("reading Artifact from file"),
-                  HasSubstr("unknown value 'Mystery' for field 'type'"))));
-}
-
-TEST_F(ArtifactTest, RoundTripTUSummary) {
-  TUSummary Summary(
-      llvm::Triple("arm64-apple-macosx"),
-      BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
-
-  Artifact A{std::move(Summary)};
-  auto WriteErr = writeArtifact(A, "tu-roundtrip.json");
-  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
-
-  PathString FilePath = makePath("tu-roundtrip.json");
-  auto ReadResult = JSONFormat().readArtifact(FilePath);
-  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<TUSummary>(*ReadResult));
-}
-
-TEST_F(ArtifactTest, RoundTripLUSummary) {
-  NestedBuildNamespace NBN(
-      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
-  LUSummary Summary(llvm::Triple("arm64-apple-macosx"), std::move(NBN));
-
-  Artifact A{std::move(Summary)};
-  auto WriteErr = writeArtifact(A, "lu-roundtrip.json");
-  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
-
-  PathString FilePath = makePath("lu-roundtrip.json");
-  auto ReadResult = JSONFormat().readArtifact(FilePath);
-  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<LUSummary>(*ReadResult));
-}
-
-TEST_F(ArtifactTest, RoundTripWPASuite) {
-  WPASuite Suite = makeWPASuite();
-
-  Artifact A{std::move(Suite)};
-  auto WriteErr = writeArtifact(A, "wpa-roundtrip.json");
-  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
-
-  PathString FilePath = makePath("wpa-roundtrip.json");
-  auto ReadResult = JSONFormat().readArtifact(FilePath);
-  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<WPASuite>(*ReadResult));
-}
-
-// ============================================================================
-// ArtifactEncoding dispatch and round-trip tests
-// ============================================================================
-
-class ArtifactEncodingTest : public JSONFormatTest {
-protected:
-  llvm::Expected<ArtifactEncoding>
-  readArtifactEncodingFromString(StringRef JSON) const {
-    auto ExpectedFilePath = writeJSON(JSON, "encoding.json");
-    if (!ExpectedFilePath) {
-      return ExpectedFilePath.takeError();
-    }
-    return JSONFormat().readArtifactEncoding(*ExpectedFilePath);
-  }
-
-  llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
-                                    StringRef FileName) {
-    PathString FilePath = makePath(FileName);
-    return JSONFormat().writeArtifactEncoding(E, FilePath);
-  }
-};
-
-TEST_F(ArtifactEncodingTest, ReadDispatchesToTUSummaryEncoding) {
-  auto Result = readArtifactEncodingFromString(R"({
-    "type": "TUSummary",
-    "tu_namespace": {
-      "kind": "CompilationUnit",
-      "name": "test.cpp"
-    },
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  ASSERT_THAT_EXPECTED(Result, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<TUSummaryEncoding>(*Result));
-}
-
-TEST_F(ArtifactEncodingTest, ReadDispatchesToLUSummaryEncoding) {
-  auto Result = readArtifactEncodingFromString(R"({
-    "type": "LUSummary",
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  ASSERT_THAT_EXPECTED(Result, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<LUSummaryEncoding>(*Result));
-}
-
-TEST_F(ArtifactEncodingTest, ReadMissingTypeField) {
-  auto Result = readArtifactEncodingFromString(R"({
-    "tu_namespace": {
-      "kind": "CompilationUnit",
-      "name": "test.cpp"
-    },
-    "target_triple": "arm64-apple-macosx",
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-
-  EXPECT_THAT_EXPECTED(
-      Result, FailedWithMessage(AllOf(
-                  HasSubstr("reading ArtifactEncoding from file"),
-                  HasSubstr("failed to read summary type from field 'type'"))));
-}
-
-TEST_F(ArtifactEncodingTest, ReadUnknownTypeField) {
-  auto Result = readArtifactEncodingFromString(R"({
-    "type": "Mystery"
-  })");
-
-  EXPECT_THAT_EXPECTED(
-      Result, FailedWithMessage(AllOf(
-                  HasSubstr("reading ArtifactEncoding from file"),
-                  HasSubstr("unknown value 'Mystery' for field 'type'"))));
-}
-
-TEST_F(ArtifactEncodingTest, RoundTripTUSummaryEncoding) {
-  TUSummaryEncoding Encoding(
-      llvm::Triple("arm64-apple-macosx"),
-      BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
-
-  ArtifactEncoding E{std::move(Encoding)};
-  auto WriteErr = writeArtifactEncoding(E, "tu-enc-roundtrip.json");
-  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
-
-  PathString FilePath = makePath("tu-enc-roundtrip.json");
-  auto ReadResult = JSONFormat().readArtifactEncoding(FilePath);
-  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<TUSummaryEncoding>(*ReadResult));
-}
-
-TEST_F(ArtifactEncodingTest, RoundTripLUSummaryEncoding) {
-  NestedBuildNamespace NBN(
-      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
-  LUSummaryEncoding Encoding(llvm::Triple("arm64-apple-macosx"),
-                             std::move(NBN));
-
-  ArtifactEncoding E{std::move(Encoding)};
-  auto WriteErr = writeArtifactEncoding(E, "lu-enc-roundtrip.json");
-  ASSERT_THAT_ERROR(std::move(WriteErr), Succeeded());
-
-  PathString FilePath = makePath("lu-enc-roundtrip.json");
-  auto ReadResult = JSONFormat().readArtifactEncoding(FilePath);
-  ASSERT_THAT_EXPECTED(ReadResult, Succeeded());
-  EXPECT_TRUE(std::holds_alternative<LUSummaryEncoding>(*ReadResult));
-}
-
-} // anonymous namespace



More information about the cfe-commits mailing list