https://github.com/NagyDonat updated 
https://github.com/llvm/llvm-project/pull/223976

From 2eff5574bbcfce0f98a15231534fe3c8e998468d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <[email protected]>
Date: Wed, 16 Sep 2026 12:20:28 +0200
Subject: [PATCH 1/2] [SSAF] Revert addition of two failing test files

As a developer of the clang static analyzer, I'm using the build target
`check-clang-analysis` [1] to build and test my changes.

This workflow was recently broken by two new SSAF testcases under
`Analysis/Scalable` that fail with "clang-apply-replacements: symbol
lookup error" on my machine (where I don't build any SSAF-specific
targets and perhaps don't have some SSAF-specific tools).

In this commit I'm reverting the addition of these two test files,
because I'm not familiar with SSAF and don't have the capacity to
troubleshoot them.

When you re-add these two test files, please make sure that they don't
have hidden dependencies that happen to be available on your machine but
cause failures elsewhere.

[1] Before the introduction of SSAF and `Analysis/Scalable`, this
target only invoked tests for the clang static analyzer. See also:
https://discourse.llvm.org/t/taking-ownership-of-clang-test-analysis/84689
---
 .../cpp-bounded-buffers-replacements.cpp      | 672 ------------------
 .../multi-tu-edits-merge.cpp                  | 206 ------
 2 files changed, 878 deletions(-)
 delete mode 100644 
clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
 delete mode 100644 
clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp

diff --git 
a/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
 
b/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
deleted file mode 100644
index 3c6d8211b85de..0000000000000
--- 
a/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
+++ /dev/null
@@ -1,672 +0,0 @@
-// A simple end-to-end test for declaration rewriting, from the source
-// code to the generated source-edit YAML. If the
-// 'clang-apply-replacements' tool is available, it also applies the
-// YAML and checks the resulting rewritten source.
-
-
-// RUN: rm -rf %t && mkdir -p %t
-// RUN: split-file %s %t
-
-// DEFINE: %{testname} = unset
-// DEFINE: %{apply_dir} = %t/%{testname}_apply
-// DEFINE: %{edits_yaml} = %{apply_dir}/%{testname}.edits.yaml
-// DEFINE: %{report_sarif} = %t/%{testname}.report.sarif
-// DEFINE: %{extract} = %clang -fsyntax-only %t/%{testname}.cpp \
-// DEFINE:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
-// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu \
-// DEFINE:   --ssaf-tu-summary-file=%t/%{testname}.tu.json
-// DEFINE: %{link} = clang-ssaf-linker %t/%{testname}.tu.json -o 
%t/%{testname}.lu.json
-// DEFINE: %{analyze} = clang-ssaf-analyzer %t/%{testname}.lu.json \
-// DEFINE:   -o %t/%{testname}.wpa.json -a UnsafeBufferReachableAnalysisResult
-// DEFINE: %{transform} = mkdir -p %{apply_dir} && %clang -fsyntax-only 
%t/%{testname}.cpp \
-// DEFINE:   --ssaf-source-transformation=cpp-bounded-buffers \
-// DEFINE:   --ssaf-global-scope-analysis-result=%t/%{testname}.wpa.json \
-// DEFINE:   --ssaf-src-edit-file=%{edits_yaml} \
-// DEFINE:   --ssaf-transformation-report-file=%{report_sarif} \
-// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu \
-// DEFINE:   --ssaf-link-unit-id=%{testname}.lu
-// DEFINE: %{apply} = clang-apply-replacements %{apply_dir}
-
-
-//--- void_buffer_ptr.cpp
-void use(void *p) {
-  ((char *)p)[5];
-}
-
-//--- void_buffer_ptr.directives
-// REDEFINE: %{testname} = void_buffer_ptr
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=VOID_BUFFER_PTR --input-file=%{edits_yaml} %s
-// VOID_BUFFER_PTR: Offset: 9
-// VOID_BUFFER_PTR: ReplacementText: 'bounded_ptr<char> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=VOID_BUFFER_PTR_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// VOID_BUFFER_PTR_APPLIED: void use(bounded_ptr<char> p)
-
-
-//--- pointer_global.cpp
-int *p;
-void use() { p[5] = 0; }
-
-//--- pointer_global.directives
-// REDEFINE: %{testname} = pointer_global
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_GLOBAL --input-file=%{edits_yaml} %s
-// POINTER_GLOBAL: Offset: 0
-// POINTER_GLOBAL: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_GLOBAL_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// POINTER_GLOBAL_APPLIED: bounded_ptr<int> p;
-
-
-//--- specifier_static.cpp
-static int *p;
-void use() { p[5] = 0; }
-
-//--- specifier_static.directives
-// REDEFINE: %{testname} = specifier_static
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=SPECIFIER_STATIC --input-file=%{edits_yaml} %s
-// SPECIFIER_STATIC: Offset: 7
-// SPECIFIER_STATIC: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=SPECIFIER_STATIC_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// SPECIFIER_STATIC_APPLIED: static bounded_ptr<int> p;
-
-
-// ============================================================================
-// Qualifiers, and their positions relative to the pointee/element type
-// ============================================================================
-
-
-//--- qualifier_const_leading.cpp
-const char *p;
-void use() { (void)p[5]; }
-
-//--- qualifier_const_leading.directives
-// REDEFINE: %{testname} = qualifier_const_leading
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_CONST_LEADING 
--input-file=%{edits_yaml} %s
-// QUALIFIER_CONST_LEADING: Offset: 0
-// QUALIFIER_CONST_LEADING: ReplacementText: 'bounded_ptr<const char> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_CONST_LEADING_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// QUALIFIER_CONST_LEADING_APPLIED: bounded_ptr<const char> p;
-
-
-//--- qualifier_const_trailing_spelled_after.cpp
-char const *p;
-void use() {
-  (void)p[5];
-}
-
-//--- qualifier_const_trailing_spelled_after.directives
-// REDEFINE: %{testname} = qualifier_const_trailing_spelled_after
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_SPELLED_AFTER 
--input-file=%{edits_yaml} %s
-// QUALIFIER_SPELLED_AFTER: Offset: 0
-// QUALIFIER_SPELLED_AFTER: ReplacementText: 'bounded_ptr<const char> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_SPELLED_AFTER_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// QUALIFIER_SPELLED_AFTER_APPLIED: bounded_ptr<const char> p;
-
-
-//--- qualifier_on_pointer_itself.cpp
-int *const p = nullptr;
-void use() { (void)p[5]; }
-
-//--- qualifier_on_pointer_itself.directives
-// REDEFINE: %{testname} = qualifier_on_pointer_itself
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_ON_POINTER 
--input-file=%{edits_yaml} %s
-// QUALIFIER_ON_POINTER: Offset: 0
-// QUALIFIER_ON_POINTER: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ON_POINTER_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
-// QUALIFIER_ON_POINTER_APPLIED: bounded_ptr<int> const p = nullptr;
-
-
-//--- qualifier_multiple_trailing.cpp
-int *volatile const p = nullptr;
-void use() { (void)p[5]; }
-
-//--- qualifier_multiple_trailing.directives
-// REDEFINE: %{testname} = qualifier_multiple_trailing
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_MULTIPLE_TRAILING 
--input-file=%{edits_yaml} %s
-// QUALIFIER_MULTIPLE_TRAILING: Offset: 0
-// QUALIFIER_MULTIPLE_TRAILING: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_MULTIPLE_TRAILING_APPLIED 
--input-file=%t/%{testname}.cpp %s %}
-// QUALIFIER_MULTIPLE_TRAILING_APPLIED: bounded_ptr<int> volatile const p = 
nullptr;
-
-
-//--- qualifier_array_element_const.cpp
-const int arr[3] = {};
-void use() { (void)arr[5]; }
-
-//--- qualifier_array_element_const.directives
-// REDEFINE: %{testname} = qualifier_array_element_const
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_ARRAY_ELEMENT 
--input-file=%{edits_yaml} %s
-// QUALIFIER_ARRAY_ELEMENT: Offset: 0
-// QUALIFIER_ARRAY_ELEMENT: ReplacementText: 'bounded_array<const int, 3>'
-// QUALIFIER_ARRAY_ELEMENT: Offset: 13
-// QUALIFIER_ARRAY_ELEMENT: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ARRAY_ELEMENT_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// QUALIFIER_ARRAY_ELEMENT_APPLIED: bounded_array<const int, 3> arr = {};
-
-
-//--- qualifier_array_multiple_trailing_reversed.cpp
-int volatile const arr[3] = {};
-void use() {
-  (void)arr[5];
-}
-
-//--- qualifier_array_multiple_trailing_reversed.directives
-// REDEFINE: %{testname} = qualifier_array_multiple_trailing_reversed
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_ARRAY_REVERSED 
--input-file=%{edits_yaml} %s
-// QUALIFIER_ARRAY_REVERSED: Offset: 0
-// QUALIFIER_ARRAY_REVERSED: ReplacementText: 'bounded_array<const volatile 
int, 3>'
-// QUALIFIER_ARRAY_REVERSED: Offset: 22
-// QUALIFIER_ARRAY_REVERSED: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ARRAY_REVERSED_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// QUALIFIER_ARRAY_REVERSED_APPLIED: bounded_array<const volatile int, 3> arr 
= {};
-
-
-//--- qualifier_leading_separated.cpp
-const static char *p;
-void use() {
-  (void)p[5];
-}
-
-//--- qualifier_leading_separated.directives
-// REDEFINE: %{testname} = qualifier_leading_separated
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_LEADING_SEPARATED 
--input-file=%{edits_yaml} %s
-// QUALIFIER_LEADING_SEPARATED: Replacements: []
-// RUN: FileCheck --check-prefix=QUALIFIER_LEADING_SEPARATED_REPORT 
--input-file=%{report_sarif} %s
-// QUALIFIER_LEADING_SEPARATED_REPORT: "text": "unexpected token between a 
leading cv-qualifier and the type"
-
-
-//--- qualifier_trailing_separated.cpp
-int /* c */ const arr[3] = {};
-void use() {
-  arr[5];
-}
-
-//--- qualifier_trailing_separated.directives
-// REDEFINE: %{testname} = qualifier_trailing_separated
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=QUALIFIER_TRAILING_SEPARATED 
--input-file=%{edits_yaml} %s
-// QUALIFIER_TRAILING_SEPARATED: Replacements: []
-// RUN: FileCheck --check-prefix=QUALIFIER_TRAILING_SEPARATED_REPORT 
--input-file=%{report_sarif} %s
-// QUALIFIER_TRAILING_SEPARATED_REPORT: "text": "unexpected token between the 
type and a trailing cv-qualifier"
-
-
-//--- array_plain.cpp
-void use() {
-  int arr[3];
-  arr[5] = 0;
-}
-
-//--- array_plain.directives
-// REDEFINE: %{testname} = array_plain
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=ARRAY_PLAIN --input-file=%{edits_yaml} %s
-// ARRAY_PLAIN: Offset: 15
-// ARRAY_PLAIN: ReplacementText: 'bounded_array<int, 3>'
-// ARRAY_PLAIN: Offset: 22
-// ARRAY_PLAIN: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=ARRAY_PLAIN_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// ARRAY_PLAIN_APPLIED: bounded_array<int, 3> arr;
-
-
-//--- array_of_pointers.cpp
-// An array of pointers: the element type is itself a pointer, but the
-// element is not dereferenced by the array rewrite, so it is reproduced
-// verbatim inside the angle brackets.
-void use() {
-  int *arr[3];
-  arr[5] = nullptr;
-}
-
-//--- array_of_pointers.directives
-// REDEFINE: %{testname} = array_of_pointers
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=ARRAY_OF_POINTERS --input-file=%{edits_yaml} 
%s
-// ARRAY_OF_POINTERS: Offset: 198
-// ARRAY_OF_POINTERS: ReplacementText: 'bounded_array<int *, 3>'
-// ARRAY_OF_POINTERS: Offset: 206
-// ARRAY_OF_POINTERS: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=ARRAY_OF_POINTERS_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// ARRAY_OF_POINTERS_APPLIED: bounded_array<int *, 3>arr;
-
-
-//--- array_multi_dim.cpp
-void use() {
-  int arr[3][4];
-  arr[5][0] = 0;
-}
-
-//--- array_multi_dim.directives
-// REDEFINE: %{testname} = array_multi_dim
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=ARRAY_MULTI_DIM --input-file=%{edits_yaml} %s
-// ARRAY_MULTI_DIM: Replacements: []
-// RUN: FileCheck --check-prefix=ARRAY_MULTI_DIM_REPORT 
--input-file=%{report_sarif} %s
-// ARRAY_MULTI_DIM_REPORT: "text": "multi-dimensional array is not yet 
rewritten"
-
-
-//--- array_incomplete.cpp
-extern int arr[];
-void use() {
-  arr[5] = 0;
-}
-
-//--- array_incomplete.directives
-// REDEFINE: %{testname} = array_incomplete
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=ARRAY_INCOMPLETE --input-file=%{edits_yaml} %s
-// ARRAY_INCOMPLETE: Replacements: []
-// RUN: FileCheck --check-prefix=ARRAY_INCOMPLETE_REPORT 
--input-file=%{report_sarif} %s
-// ARRAY_INCOMPLETE_REPORT: "text": "array of unknown bound is not yet 
rewritten"
-
-
-//--- array_of_function_pointers_raw.cpp
-void use() {
-  void (*arr[4])();
-  arr[5]();
-}
-
-//--- array_of_function_pointers_raw.directives
-// REDEFINE: %{testname} = array_of_function_pointers_raw
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=ARRAY_RAW_FNPTR --input-file=%{edits_yaml} %s
-// ARRAY_RAW_FNPTR: Replacements: []
-// RUN: FileCheck --check-prefix=ARRAY_RAW_FNPTR_REPORT 
--input-file=%{report_sarif} %s
-// ARRAY_RAW_FNPTR_REPORT: "text": "the array type does not end in a closing 
bracket"
-
-
-//--- pointer_local_alias.cpp
-void use(int *p) {
-  int *q = p;
-  q[5] = 0;
-}
-
-//--- pointer_local_alias.directives
-// REDEFINE: %{testname} = pointer_local_alias
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_LOCAL_ALIAS 
--input-file=%{edits_yaml} %s
-// POINTER_LOCAL_ALIAS: Offset: 9
-// POINTER_LOCAL_ALIAS: ReplacementText: 'bounded_ptr<int> '
-// POINTER_LOCAL_ALIAS: Offset: 21
-// POINTER_LOCAL_ALIAS: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_LOCAL_ALIAS_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// POINTER_LOCAL_ALIAS_APPLIED: void use(bounded_ptr<int> p) {
-// POINTER_LOCAL_ALIAS_APPLIED-NEXT: bounded_ptr<int> q = p;
-
-
-//--- pointer_return_value.cpp
-// A reachable function return value.
-int *get(int *p) {
-  p[5] = 0;
-  return p;
-}
-
-//--- pointer_return_value.directives
-// REDEFINE: %{testname} = pointer_return_value
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_RETURN_VALUE 
--input-file=%{edits_yaml} %s
-// POINTER_RETURN_VALUE: Offset: 47
-// POINTER_RETURN_VALUE: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_RETURN_VALUE_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
-// POINTER_RETURN_VALUE_APPLIED: int *get(bounded_ptr<int> p) {
-
-
-//--- pointer_multi_level.cpp
-void use(int **pp) {
-  pp[5] = nullptr;
-  (*pp)[5] = 0;
-}
-
-//--- pointer_multi_level.directives
-// REDEFINE: %{testname} = pointer_multi_level
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_MULTI_LEVEL 
--input-file=%{edits_yaml} %s
-// POINTER_MULTI_LEVEL: Replacements: []
-// RUN: FileCheck --check-prefix=POINTER_MULTI_LEVEL_REPORT 
--input-file=%{report_sarif} %s
-// POINTER_MULTI_LEVEL_REPORT: "text": "multi-level pointer indirection is not 
yet rewritten"
-
-
-//--- pointer_to_array.cpp
-void use(int (*p)[3]) {
-  p[5][0] = 0;
-}
-
-//--- pointer_to_array.directives
-// REDEFINE: %{testname} = pointer_to_array
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_TO_ARRAY --input-file=%{edits_yaml} %s
-// POINTER_TO_ARRAY: Replacements: []
-// RUN: FileCheck --check-prefix=POINTER_TO_ARRAY_REPORT 
--input-file=%{report_sarif} %s
-// POINTER_TO_ARRAY_REPORT: "text": "pointer to array is not yet rewritten"
-
-
-//--- reference_to_pointer.cpp
-void use(int *&p) {
-  p[5] = 0;
-}
-
-//--- reference_to_pointer.directives
-// REDEFINE: %{testname} = reference_to_pointer
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=REFERENCE_TO_POINTER 
--input-file=%{edits_yaml} %s
-// REFERENCE_TO_POINTER: Replacements: []
-// RUN: FileCheck --check-prefix=REFERENCE_TO_POINTER_REPORT 
--input-file=%{report_sarif} %s
-// REFERENCE_TO_POINTER_REPORT: "text": "reference to pointer is not yet 
rewritten"
-
-
-//--- pointer_parenthesized_declarator.cpp
-void use() {
-  int v = 0;
-  int (*p) = &v;
-  (void)p[5];
-}
-
-//--- pointer_parenthesized_declarator.directives
-// REDEFINE: %{testname} = pointer_parenthesized_declarator
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=POINTER_PARENTHESIZED 
--input-file=%{edits_yaml} %s
-// POINTER_PARENTHESIZED: Replacements: []
-// RUN: FileCheck --check-prefix=POINTER_PARENTHESIZED_REPORT 
--input-file=%{report_sarif} %s
-// POINTER_PARENTHESIZED_REPORT: "text": "pointer declarator does not end at 
its '*'"
-
-
-//--- field_pointer.cpp
-struct S{int *p;};
-void use(S *w) {
-  w->p[5] = 0;
-}
-
-//--- field_pointer.directives
-// REDEFINE: %{testname} = field_pointer
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=FIELD_POINTER --input-file=%{edits_yaml} %s
-// FIELD_POINTER: Offset: 9
-// FIELD_POINTER: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=FIELD_POINTER_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// FIELD_POINTER_APPLIED: struct S{bounded_ptr<int> p;};
-
-
-//--- field_array.cpp
-// An array-typed struct field.
-struct S{int arr[3];};
-void use(S *w) {
-  w->arr[5] = 0;
-}
-
-//--- field_array.directives
-// REDEFINE: %{testname} = field_array
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=FIELD_ARRAY --input-file=%{edits_yaml} %s
-// FIELD_ARRAY: Offset: 41
-// FIELD_ARRAY: ReplacementText: 'bounded_array<int, 3>'
-// FIELD_ARRAY: Offset: 48
-// FIELD_ARRAY: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=FIELD_ARRAY_APPLIED --input-file=%t/%{testname}.cpp %s %}
-// FIELD_ARRAY_APPLIED: struct S{bounded_array<int, 3> arr;};
-
-
-// ============================================================================
-// Macros
-// ============================================================================
-
-//--- macro_expansion.cpp
-// Skip MacroExpansion: the declarator's type is spelled through a macro.
-#define PTR int *
-void use(PTR p) {
-  p[5] = 0;
-}
-
-//--- macro_expansion.directives
-// REDEFINE: %{testname} = macro_expansion
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=MACRO_EXPANSION --input-file=%{edits_yaml} %s
-// MACRO_EXPANSION: Replacements: []
-// RUN: FileCheck --check-prefix=MACRO_EXPANSION_REPORT 
--input-file=%{report_sarif} %s
-// MACRO_EXPANSION_REPORT: "text": "declarator spelled through a macro is not 
yet rewritten"
-
-
-// ============================================================================
-// Typedefs
-// ============================================================================
-
-//--- typedef_array_of_function_pointers.cpp
-// A typedef used as an array element type does not block the array rewrite:
-// the typedef keeps the declarator a clean prefix + [N] suffix, so only the
-// (unexpanded) element spelling changes.
-typedef void (*FP)();
-void use() {
-  FP arr[4];
-  arr[5]();
-}
-
-//--- typedef_array_of_function_pointers.directives
-// REDEFINE: %{testname} = typedef_array_of_function_pointers
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=TYPEDEF_ARRAY_OF_FNPTRS 
--input-file=%{edits_yaml} %s
-// TYPEDEF_ARRAY_OF_FNPTRS: Offset: 233
-// TYPEDEF_ARRAY_OF_FNPTRS: ReplacementText: 'bounded_array<FP, 4>'
-// TYPEDEF_ARRAY_OF_FNPTRS: Offset: 239
-// TYPEDEF_ARRAY_OF_FNPTRS: ReplacementText: ''
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=TYPEDEF_ARRAY_OF_FNPTRS_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// TYPEDEF_ARRAY_OF_FNPTRS_APPLIED: bounded_array<FP, 4> arr;
-
-
-//--- typedef_pointer.cpp
-typedef int *P;
-void use(P p) {
-  p[5] = 0;
-}
-
-//--- typedef_pointer.directives
-// REDEFINE: %{testname} = typedef_pointer
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=TYPEDEF_POINTER --input-file=%{edits_yaml} %s
-// TYPEDEF_POINTER: Replacements: []
-// RUN: FileCheck --check-prefix=TYPEDEF_POINTER_REPORT 
--input-file=%{report_sarif} %s
-// TYPEDEF_POINTER_REPORT: "text": "no TypeLoc for the pointee or array 
element type"
-
-
-//--- unnamable_anonymous_struct.cpp
-struct { int x; } *p;
-void use(int i) {
-  p[i].x = 0;
-}
-
-//--- unnamable_anonymous_struct.directives
-// REDEFINE: %{testname} = unnamable_anonymous_struct
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=UNNAMABLE_ANON_STRUCT 
--input-file=%{edits_yaml} %s
-// UNNAMABLE_ANON_STRUCT: Replacements: []
-// RUN: FileCheck --check-prefix=UNNAMABLE_ANON_STRUCT_REPORT 
--input-file=%{report_sarif} %s
-// UNNAMABLE_ANON_STRUCT_REPORT: "text": "the pointee or array element type 
has no name that can be written as a template argument"
-
-
-//--- unnamable_lambda_decltype.cpp
-void use() {
-  auto f = [](int x) { return x; };
-  decltype(f) *p = &f;
-  (void)p[5];
-}
-
-//--- unnamable_lambda_decltype.directives
-// REDEFINE: %{testname} = unnamable_lambda_decltype
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=UNNAMABLE_LAMBDA --input-file=%{edits_yaml} %s
-// UNNAMABLE_LAMBDA: Replacements: []
-// RUN: FileCheck --check-prefix=UNNAMABLE_LAMBDA_REPORT 
--input-file=%{report_sarif} %s
-// UNNAMABLE_LAMBDA_REPORT: "text": "the pointee or array element type has no 
name that can be written as a template argument"
-
-
-//--- whitespace_free_pointer.cpp
-int*p;
-void use(){p[5]=0;}
-
-//--- whitespace_free_pointer.directives
-// REDEFINE: %{testname} = whitespace_free_pointer
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=WHITESPACE_FREE_POINTER 
--input-file=%{edits_yaml} %s
-// WHITESPACE_FREE_POINTER: Offset: 0
-// WHITESPACE_FREE_POINTER: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=WHITESPACE_FREE_POINTER_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
-// WHITESPACE_FREE_POINTER_APPLIED: bounded_ptr<int> p;
-
-
-//--- skip_declaration_group.cpp
-void use() {
-  int *a, *b;
-  a[5] = 0;
-  b[5] = 0;
-}
-
-//--- skip_declaration_group.directives
-// REDEFINE: %{testname} = skip_declaration_group
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=SKIP_DECL_GROUP --input-file=%{edits_yaml} %s
-// SKIP_DECL_GROUP: Replacements: []
-// RUN: FileCheck --check-prefix=SKIP_DECL_GROUP_REPORT 
--input-file=%{report_sarif} %s
-// SKIP_DECL_GROUP_REPORT-DAG: "text": "declarator of a multi-declarator group 
is not yet rewritten"
-
-
-//--- skip_trailing_return_type.cpp
-auto f(int *p) -> int * {
-  return p;
-}
-void use() {
-  int *q = f(nullptr);
-  q[5] = 0;
-}
-
-//--- skip_trailing_return_type.directives
-// REDEFINE: %{testname} = skip_trailing_return_type
-// RUN: %{extract}
-// RUN: %{link}
-// RUN: %{analyze}
-// RUN: %{transform}
-// RUN: FileCheck --check-prefix=SKIP_TRAILING_RETURN_REPORT 
--input-file=%{report_sarif} %s
-// SKIP_TRAILING_RETURN_REPORT: "text": "trailing return type is not yet 
rewritten"
-// RUN: FileCheck --check-prefix=SKIP_TRAILING_RETURN 
--input-file=%{edits_yaml} %s
-// SKIP_TRAILING_RETURN: Offset: 7
-// SKIP_TRAILING_RETURN: ReplacementText: 'bounded_ptr<int> '
-// SKIP_TRAILING_RETURN: Offset: 55
-// SKIP_TRAILING_RETURN: ReplacementText: 'bounded_ptr<int> '
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=SKIP_TRAILING_RETURN_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
-// SKIP_TRAILING_RETURN_APPLIED: auto f(bounded_ptr<int> p) -> int * {
-// SKIP_TRAILING_RETURN_APPLIED: bounded_ptr<int> q = f(nullptr);
diff --git 
a/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp 
b/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp
deleted file mode 100644
index 7057a2a6ed078..0000000000000
--- 
a/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-// Tests clang-ssaf-src-edit-merge against real multi-TU source.
-// Specifically, this file tests non-conflicting merges across multiple TUs.
-
-// RUN: rm -rf %t && mkdir -p %t
-// RUN: split-file %s %t
-
-// DEFINE: %{casedir} = unset
-// DEFINE: %{testname} = unset
-// DEFINE: %{tu_json} = %{casedir}/%{testname}.tu.json
-// DEFINE: %{lu_json} = %{casedir}/%{testname}.lu.json
-// DEFINE: %{wpa_json} = %{casedir}/%{testname}.wpa.json
-// DEFINE: %{apply_dir} = %{casedir}/%{testname}_apply
-// DEFINE: %{edits_yaml} = %{apply_dir}/%{testname}.edits.yaml
-// DEFINE: %{extract} = %clang -fsyntax-only %{casedir}/%{testname}.cpp \
-// DEFINE:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
-// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu 
--ssaf-tu-summary-file=%{tu_json}
-// DEFINE: %{link} = clang-ssaf-linker %{tu_json} -o %{lu_json}
-// DEFINE: %{analyze} = clang-ssaf-analyzer %{lu_json} -o %{wpa_json} -a 
UnsafeBufferReachableAnalysisResult
-// DEFINE: %{transform} = mkdir -p %{apply_dir} && %clang -fsyntax-only 
%{casedir}/%{testname}.cpp \
-// DEFINE:   --ssaf-source-transformation=cpp-bounded-buffers \
-// DEFINE:   --ssaf-global-scope-analysis-result=%{wpa_json} \
-// DEFINE:   --ssaf-src-edit-file=%{edits_yaml} \
-// DEFINE:   
--ssaf-transformation-report-file=%{casedir}/%{testname}.report.sarif \
-// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu 
--ssaf-link-unit-id=%{testname}.lu
-// DEFINE: %{pipeline} = %{extract} && %{link} && %{analyze} && %{transform}
-// DEFINE: %{merge_inputs} = unset
-// DEFINE: %{merge} = mkdir -p %{casedir}/merge_apply && 
clang-ssaf-src-edit-merge %{merge_inputs} -o %{casedir}/merge_apply/merged.yaml 
--sarif-conflicts-out=%{casedir}/conflicts.sarif 2> %{casedir}/merge.stderr
-// DEFINE: %{apply} = clang-apply-replacements %{casedir}/merge_apply
-
-//--- distinct-files/a.h
-int *ga;
-
-//--- distinct-files/b.h
-int *gb;
-
-//--- distinct-files/a.cpp
-#include "a.h"
-void use_a() { ga[5] = 0; }
-
-//--- distinct-files/b.cpp
-#include "b.h"
-void use_b() { gb[7] = 0; }
-
-// REDEFINE: %{casedir} = %t/distinct-files
-// REDEFINE: %{testname} = a
-// RUN: %{pipeline}
-// REDEFINE: %{testname} = b
-// RUN: %{pipeline}
-
-// REDEFINE: %{merge_inputs} = %t/distinct-files/a_apply/a.edits.yaml 
%t/distinct-files/b_apply/b.edits.yaml
-// RUN: %{merge}
-
-// Both survive, different files:
-// RUN: FileCheck --check-prefix=DF_MERGED 
--input-file=%t/distinct-files/merge_apply/merged.yaml %s
-// DF_MERGED: FilePath:
-// DF_MERGED-SAME: a.h
-// DF_MERGED: FilePath:
-// DF_MERGED-SAME: b.h
-
-// RUN: FileCheck --check-prefix=DF_NOSTDERR 
--input-file=%t/distinct-files/merge.stderr --allow-empty %s
-// DF_NOSTDERR-NOT: conflict:
-
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DF_A_APPLIED 
--input-file=%t/distinct-files/a.h %s %}
-// DF_A_APPLIED: bounded_ptr<int> ga;
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DF_B_APPLIED 
--input-file=%t/distinct-files/b.h %s %}
-// DF_B_APPLIED: bounded_ptr<int> gb;
-
-
-//--- distinct-locations/shared.h
-int *g1;
-int *g2;
-
-//--- distinct-locations/a.cpp
-#include "shared.h"
-void use_a() { g1[5] = 0; }
-
-//--- distinct-locations/b.cpp
-#include "shared.h"
-void use_b() { g2[7] = 0; }
-
-// REDEFINE: %{casedir} = %t/distinct-locations
-// REDEFINE: %{testname} = a
-// RUN: %{pipeline}
-// REDEFINE: %{testname} = b
-// RUN: %{pipeline}
-
-// REDEFINE: %{merge_inputs} = %t/distinct-locations/a_apply/a.edits.yaml 
%t/distinct-locations/b_apply/b.edits.yaml
-// RUN: %{merge}
-
-// Both survive, same file, distinct offsets:
-// RUN: FileCheck --check-prefix=DL_MERGED 
--input-file=%t/distinct-locations/merge_apply/merged.yaml %s
-// DL_MERGED: Offset:          0
-// DL_MERGED-NEXT: Length:          5
-// DL_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
-// DL_MERGED: Offset:          9
-// DL_MERGED-NEXT: Length:          5
-// DL_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
-
-// RUN: FileCheck --check-prefix=DL_NOSTDERR 
--input-file=%t/distinct-locations/merge.stderr --allow-empty %s
-// DL_NOSTDERR-NOT: conflict:
-
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DL_APPLIED 
--input-file=%t/distinct-locations/shared.h %s %}
-// DL_APPLIED: bounded_ptr<int> g1;
-// DL_APPLIED-NEXT: bounded_ptr<int> g2;
-
-
-//--- three-tu-distinct/shared.h
-int *g1;int *g2;int *g3;
-
-//--- three-tu-distinct/a.cpp
-#include "shared.h"
-void use_a() { g1[5] = 0; }
-
-//--- three-tu-distinct/b.cpp
-#include "shared.h"
-void use_b() { g2[7] = 0; }
-
-//--- three-tu-distinct/c.cpp
-#include "shared.h"
-void use_c() { g3[9] = 0; }
-
-// REDEFINE: %{casedir} = %t/three-tu-distinct
-// REDEFINE: %{testname} = a
-// RUN: %{pipeline}
-// REDEFINE: %{testname} = b
-// RUN: %{pipeline}
-// REDEFINE: %{testname} = c
-// RUN: %{pipeline}
-
-// REDEFINE: %{merge_inputs} = %t/three-tu-distinct/a_apply/a.edits.yaml 
%t/three-tu-distinct/b_apply/b.edits.yaml 
%t/three-tu-distinct/c_apply/c.edits.yaml
-// RUN: %{merge}
-
-// All three survive:
-// RUN: FileCheck --check-prefix=TTD_MERGED 
--input-file=%t/three-tu-distinct/merge_apply/merged.yaml %s
-// TTD_MERGED: Offset:          0
-// TTD_MERGED: Offset:          8
-// TTD_MERGED: Offset:          16
-
-// RUN: FileCheck --check-prefix=TTD_NOSTDERR 
--input-file=%t/three-tu-distinct/merge.stderr --allow-empty %s
-// TTD_NOSTDERR-NOT: conflict:
-
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=TTD_APPLIED 
--input-file=%t/three-tu-distinct/shared.h %s %}
-// TTD_APPLIED: bounded_ptr<int> g1;bounded_ptr<int> g2;bounded_ptr<int> g3;
-
-
-//--- static-inline-fun-dedup/shared.h
-static inline int * foo(int *p) {
-  return p;
-}
-
-//--- static-inline-fun-dedup/a.cpp
-#include "shared.h"
-void caller(int * p) { int * q = foo(p); q[5] = 0; }
-
-//--- static-inline-fun-dedup/b.cpp
-#include "shared.h"
-void caller(int * p) { int * q = foo(p); q[5] = 0; }
-
-// REDEFINE: %{casedir} = %t/static-inline-fun-dedup
-// REDEFINE: %{testname} = a
-// RUN: %{pipeline}
-// REDEFINE: %{testname} = b
-// RUN: %{pipeline}
-
-// REDEFINE: %{merge_inputs} = %t/static-inline-fun-dedup/a_apply/a.edits.yaml 
%t/static-inline-fun-dedup/b_apply/b.edits.yaml
-// RUN: %{merge}
-
-// Shared static-linkage function's rewrite dedups; each caller's own file
-// still survives on its own:
-// RUN: FileCheck --check-prefix=SIF_MERGED 
--input-file=%t/static-inline-fun-dedup/merge_apply/merged.yaml %s
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: a.cpp
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: a.cpp
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: b.cpp
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: b.cpp
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: shared.h
-// SIF_MERGED-NEXT: Offset:          14
-// SIF_MERGED-NEXT: Length:          5
-// SIF_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
-// SIF_MERGED: FilePath:
-// SIF_MERGED-SAME: shared.h
-// SIF_MERGED-NEXT: Offset:          24
-// SIF_MERGED-NEXT: Length:          5
-// SIF_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
-// SIF_MERGED-NOT: FilePath:
-
-// RUN: FileCheck --check-prefix=SIF_NOSTDERR 
--input-file=%t/static-inline-fun-dedup/merge.stderr --allow-empty %s
-// SIF_NOSTDERR-NOT: conflict:
-
-// RUN: %if clang-apply-replacements %{ %{apply} %}
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_H_APPLIED 
--input-file=%t/static-inline-fun-dedup/shared.h %s %}
-// SIF_H_APPLIED: static inline bounded_ptr<int> foo(bounded_ptr<int> p) {
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_A_APPLIED 
--input-file=%t/static-inline-fun-dedup/a.cpp %s %}
-// SIF_A_APPLIED: void caller(bounded_ptr<int> p) { bounded_ptr<int> q = 
foo(p); q[5] = 0; }
-// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_B_APPLIED 
--input-file=%t/static-inline-fun-dedup/b.cpp %s %}
-// SIF_B_APPLIED: void caller(bounded_ptr<int> p) { bounded_ptr<int> q = 
foo(p); q[5] = 0; }
-
-
-

From 2b8282c9d957945908d4c619e50ed522906f7e3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <[email protected]>
Date: Wed, 16 Sep 2026 13:20:54 +0200
Subject: [PATCH 2/2] Only mark the tests as unsupported instead of deleting
 them

---
 .../cpp-bounded-buffers-replacements.cpp      | 673 ++++++++++++++++++
 .../multi-tu-edits-merge.cpp                  | 208 ++++++
 2 files changed, 881 insertions(+)
 create mode 100644 
clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
 create mode 100644 
clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp

diff --git 
a/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
 
b/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
new file mode 100644
index 0000000000000..de33fa1be44a6
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/source-edit-generation/cpp-bounded-buffers-replacements.cpp
@@ -0,0 +1,673 @@
+// A simple end-to-end test for declaration rewriting, from the source
+// code to the generated source-edit YAML. If the
+// 'clang-apply-replacements' tool is available, it also applies the
+// YAML and checks the resulting rewritten source.
+
+// UNSUPPORTED: target={{.*}}
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// DEFINE: %{testname} = unset
+// DEFINE: %{apply_dir} = %t/%{testname}_apply
+// DEFINE: %{edits_yaml} = %{apply_dir}/%{testname}.edits.yaml
+// DEFINE: %{report_sarif} = %t/%{testname}.report.sarif
+// DEFINE: %{extract} = %clang -fsyntax-only %t/%{testname}.cpp \
+// DEFINE:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
+// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu \
+// DEFINE:   --ssaf-tu-summary-file=%t/%{testname}.tu.json
+// DEFINE: %{link} = clang-ssaf-linker %t/%{testname}.tu.json -o 
%t/%{testname}.lu.json
+// DEFINE: %{analyze} = clang-ssaf-analyzer %t/%{testname}.lu.json \
+// DEFINE:   -o %t/%{testname}.wpa.json -a UnsafeBufferReachableAnalysisResult
+// DEFINE: %{transform} = mkdir -p %{apply_dir} && %clang -fsyntax-only 
%t/%{testname}.cpp \
+// DEFINE:   --ssaf-source-transformation=cpp-bounded-buffers \
+// DEFINE:   --ssaf-global-scope-analysis-result=%t/%{testname}.wpa.json \
+// DEFINE:   --ssaf-src-edit-file=%{edits_yaml} \
+// DEFINE:   --ssaf-transformation-report-file=%{report_sarif} \
+// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu \
+// DEFINE:   --ssaf-link-unit-id=%{testname}.lu
+// DEFINE: %{apply} = clang-apply-replacements %{apply_dir}
+
+
+//--- void_buffer_ptr.cpp
+void use(void *p) {
+  ((char *)p)[5];
+}
+
+//--- void_buffer_ptr.directives
+// REDEFINE: %{testname} = void_buffer_ptr
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=VOID_BUFFER_PTR --input-file=%{edits_yaml} %s
+// VOID_BUFFER_PTR: Offset: 9
+// VOID_BUFFER_PTR: ReplacementText: 'bounded_ptr<char> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=VOID_BUFFER_PTR_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// VOID_BUFFER_PTR_APPLIED: void use(bounded_ptr<char> p)
+
+
+//--- pointer_global.cpp
+int *p;
+void use() { p[5] = 0; }
+
+//--- pointer_global.directives
+// REDEFINE: %{testname} = pointer_global
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_GLOBAL --input-file=%{edits_yaml} %s
+// POINTER_GLOBAL: Offset: 0
+// POINTER_GLOBAL: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_GLOBAL_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// POINTER_GLOBAL_APPLIED: bounded_ptr<int> p;
+
+
+//--- specifier_static.cpp
+static int *p;
+void use() { p[5] = 0; }
+
+//--- specifier_static.directives
+// REDEFINE: %{testname} = specifier_static
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=SPECIFIER_STATIC --input-file=%{edits_yaml} %s
+// SPECIFIER_STATIC: Offset: 7
+// SPECIFIER_STATIC: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=SPECIFIER_STATIC_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// SPECIFIER_STATIC_APPLIED: static bounded_ptr<int> p;
+
+
+// ============================================================================
+// Qualifiers, and their positions relative to the pointee/element type
+// ============================================================================
+
+
+//--- qualifier_const_leading.cpp
+const char *p;
+void use() { (void)p[5]; }
+
+//--- qualifier_const_leading.directives
+// REDEFINE: %{testname} = qualifier_const_leading
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_CONST_LEADING 
--input-file=%{edits_yaml} %s
+// QUALIFIER_CONST_LEADING: Offset: 0
+// QUALIFIER_CONST_LEADING: ReplacementText: 'bounded_ptr<const char> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_CONST_LEADING_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// QUALIFIER_CONST_LEADING_APPLIED: bounded_ptr<const char> p;
+
+
+//--- qualifier_const_trailing_spelled_after.cpp
+char const *p;
+void use() {
+  (void)p[5];
+}
+
+//--- qualifier_const_trailing_spelled_after.directives
+// REDEFINE: %{testname} = qualifier_const_trailing_spelled_after
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_SPELLED_AFTER 
--input-file=%{edits_yaml} %s
+// QUALIFIER_SPELLED_AFTER: Offset: 0
+// QUALIFIER_SPELLED_AFTER: ReplacementText: 'bounded_ptr<const char> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_SPELLED_AFTER_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// QUALIFIER_SPELLED_AFTER_APPLIED: bounded_ptr<const char> p;
+
+
+//--- qualifier_on_pointer_itself.cpp
+int *const p = nullptr;
+void use() { (void)p[5]; }
+
+//--- qualifier_on_pointer_itself.directives
+// REDEFINE: %{testname} = qualifier_on_pointer_itself
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_ON_POINTER 
--input-file=%{edits_yaml} %s
+// QUALIFIER_ON_POINTER: Offset: 0
+// QUALIFIER_ON_POINTER: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ON_POINTER_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
+// QUALIFIER_ON_POINTER_APPLIED: bounded_ptr<int> const p = nullptr;
+
+
+//--- qualifier_multiple_trailing.cpp
+int *volatile const p = nullptr;
+void use() { (void)p[5]; }
+
+//--- qualifier_multiple_trailing.directives
+// REDEFINE: %{testname} = qualifier_multiple_trailing
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_MULTIPLE_TRAILING 
--input-file=%{edits_yaml} %s
+// QUALIFIER_MULTIPLE_TRAILING: Offset: 0
+// QUALIFIER_MULTIPLE_TRAILING: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_MULTIPLE_TRAILING_APPLIED 
--input-file=%t/%{testname}.cpp %s %}
+// QUALIFIER_MULTIPLE_TRAILING_APPLIED: bounded_ptr<int> volatile const p = 
nullptr;
+
+
+//--- qualifier_array_element_const.cpp
+const int arr[3] = {};
+void use() { (void)arr[5]; }
+
+//--- qualifier_array_element_const.directives
+// REDEFINE: %{testname} = qualifier_array_element_const
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_ARRAY_ELEMENT 
--input-file=%{edits_yaml} %s
+// QUALIFIER_ARRAY_ELEMENT: Offset: 0
+// QUALIFIER_ARRAY_ELEMENT: ReplacementText: 'bounded_array<const int, 3>'
+// QUALIFIER_ARRAY_ELEMENT: Offset: 13
+// QUALIFIER_ARRAY_ELEMENT: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ARRAY_ELEMENT_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// QUALIFIER_ARRAY_ELEMENT_APPLIED: bounded_array<const int, 3> arr = {};
+
+
+//--- qualifier_array_multiple_trailing_reversed.cpp
+int volatile const arr[3] = {};
+void use() {
+  (void)arr[5];
+}
+
+//--- qualifier_array_multiple_trailing_reversed.directives
+// REDEFINE: %{testname} = qualifier_array_multiple_trailing_reversed
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_ARRAY_REVERSED 
--input-file=%{edits_yaml} %s
+// QUALIFIER_ARRAY_REVERSED: Offset: 0
+// QUALIFIER_ARRAY_REVERSED: ReplacementText: 'bounded_array<const volatile 
int, 3>'
+// QUALIFIER_ARRAY_REVERSED: Offset: 22
+// QUALIFIER_ARRAY_REVERSED: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=QUALIFIER_ARRAY_REVERSED_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// QUALIFIER_ARRAY_REVERSED_APPLIED: bounded_array<const volatile int, 3> arr 
= {};
+
+
+//--- qualifier_leading_separated.cpp
+const static char *p;
+void use() {
+  (void)p[5];
+}
+
+//--- qualifier_leading_separated.directives
+// REDEFINE: %{testname} = qualifier_leading_separated
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_LEADING_SEPARATED 
--input-file=%{edits_yaml} %s
+// QUALIFIER_LEADING_SEPARATED: Replacements: []
+// RUN: FileCheck --check-prefix=QUALIFIER_LEADING_SEPARATED_REPORT 
--input-file=%{report_sarif} %s
+// QUALIFIER_LEADING_SEPARATED_REPORT: "text": "unexpected token between a 
leading cv-qualifier and the type"
+
+
+//--- qualifier_trailing_separated.cpp
+int /* c */ const arr[3] = {};
+void use() {
+  arr[5];
+}
+
+//--- qualifier_trailing_separated.directives
+// REDEFINE: %{testname} = qualifier_trailing_separated
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=QUALIFIER_TRAILING_SEPARATED 
--input-file=%{edits_yaml} %s
+// QUALIFIER_TRAILING_SEPARATED: Replacements: []
+// RUN: FileCheck --check-prefix=QUALIFIER_TRAILING_SEPARATED_REPORT 
--input-file=%{report_sarif} %s
+// QUALIFIER_TRAILING_SEPARATED_REPORT: "text": "unexpected token between the 
type and a trailing cv-qualifier"
+
+
+//--- array_plain.cpp
+void use() {
+  int arr[3];
+  arr[5] = 0;
+}
+
+//--- array_plain.directives
+// REDEFINE: %{testname} = array_plain
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=ARRAY_PLAIN --input-file=%{edits_yaml} %s
+// ARRAY_PLAIN: Offset: 15
+// ARRAY_PLAIN: ReplacementText: 'bounded_array<int, 3>'
+// ARRAY_PLAIN: Offset: 22
+// ARRAY_PLAIN: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=ARRAY_PLAIN_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// ARRAY_PLAIN_APPLIED: bounded_array<int, 3> arr;
+
+
+//--- array_of_pointers.cpp
+// An array of pointers: the element type is itself a pointer, but the
+// element is not dereferenced by the array rewrite, so it is reproduced
+// verbatim inside the angle brackets.
+void use() {
+  int *arr[3];
+  arr[5] = nullptr;
+}
+
+//--- array_of_pointers.directives
+// REDEFINE: %{testname} = array_of_pointers
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=ARRAY_OF_POINTERS --input-file=%{edits_yaml} 
%s
+// ARRAY_OF_POINTERS: Offset: 198
+// ARRAY_OF_POINTERS: ReplacementText: 'bounded_array<int *, 3>'
+// ARRAY_OF_POINTERS: Offset: 206
+// ARRAY_OF_POINTERS: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=ARRAY_OF_POINTERS_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// ARRAY_OF_POINTERS_APPLIED: bounded_array<int *, 3>arr;
+
+
+//--- array_multi_dim.cpp
+void use() {
+  int arr[3][4];
+  arr[5][0] = 0;
+}
+
+//--- array_multi_dim.directives
+// REDEFINE: %{testname} = array_multi_dim
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=ARRAY_MULTI_DIM --input-file=%{edits_yaml} %s
+// ARRAY_MULTI_DIM: Replacements: []
+// RUN: FileCheck --check-prefix=ARRAY_MULTI_DIM_REPORT 
--input-file=%{report_sarif} %s
+// ARRAY_MULTI_DIM_REPORT: "text": "multi-dimensional array is not yet 
rewritten"
+
+
+//--- array_incomplete.cpp
+extern int arr[];
+void use() {
+  arr[5] = 0;
+}
+
+//--- array_incomplete.directives
+// REDEFINE: %{testname} = array_incomplete
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=ARRAY_INCOMPLETE --input-file=%{edits_yaml} %s
+// ARRAY_INCOMPLETE: Replacements: []
+// RUN: FileCheck --check-prefix=ARRAY_INCOMPLETE_REPORT 
--input-file=%{report_sarif} %s
+// ARRAY_INCOMPLETE_REPORT: "text": "array of unknown bound is not yet 
rewritten"
+
+
+//--- array_of_function_pointers_raw.cpp
+void use() {
+  void (*arr[4])();
+  arr[5]();
+}
+
+//--- array_of_function_pointers_raw.directives
+// REDEFINE: %{testname} = array_of_function_pointers_raw
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=ARRAY_RAW_FNPTR --input-file=%{edits_yaml} %s
+// ARRAY_RAW_FNPTR: Replacements: []
+// RUN: FileCheck --check-prefix=ARRAY_RAW_FNPTR_REPORT 
--input-file=%{report_sarif} %s
+// ARRAY_RAW_FNPTR_REPORT: "text": "the array type does not end in a closing 
bracket"
+
+
+//--- pointer_local_alias.cpp
+void use(int *p) {
+  int *q = p;
+  q[5] = 0;
+}
+
+//--- pointer_local_alias.directives
+// REDEFINE: %{testname} = pointer_local_alias
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_LOCAL_ALIAS 
--input-file=%{edits_yaml} %s
+// POINTER_LOCAL_ALIAS: Offset: 9
+// POINTER_LOCAL_ALIAS: ReplacementText: 'bounded_ptr<int> '
+// POINTER_LOCAL_ALIAS: Offset: 21
+// POINTER_LOCAL_ALIAS: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_LOCAL_ALIAS_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// POINTER_LOCAL_ALIAS_APPLIED: void use(bounded_ptr<int> p) {
+// POINTER_LOCAL_ALIAS_APPLIED-NEXT: bounded_ptr<int> q = p;
+
+
+//--- pointer_return_value.cpp
+// A reachable function return value.
+int *get(int *p) {
+  p[5] = 0;
+  return p;
+}
+
+//--- pointer_return_value.directives
+// REDEFINE: %{testname} = pointer_return_value
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_RETURN_VALUE 
--input-file=%{edits_yaml} %s
+// POINTER_RETURN_VALUE: Offset: 47
+// POINTER_RETURN_VALUE: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=POINTER_RETURN_VALUE_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
+// POINTER_RETURN_VALUE_APPLIED: int *get(bounded_ptr<int> p) {
+
+
+//--- pointer_multi_level.cpp
+void use(int **pp) {
+  pp[5] = nullptr;
+  (*pp)[5] = 0;
+}
+
+//--- pointer_multi_level.directives
+// REDEFINE: %{testname} = pointer_multi_level
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_MULTI_LEVEL 
--input-file=%{edits_yaml} %s
+// POINTER_MULTI_LEVEL: Replacements: []
+// RUN: FileCheck --check-prefix=POINTER_MULTI_LEVEL_REPORT 
--input-file=%{report_sarif} %s
+// POINTER_MULTI_LEVEL_REPORT: "text": "multi-level pointer indirection is not 
yet rewritten"
+
+
+//--- pointer_to_array.cpp
+void use(int (*p)[3]) {
+  p[5][0] = 0;
+}
+
+//--- pointer_to_array.directives
+// REDEFINE: %{testname} = pointer_to_array
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_TO_ARRAY --input-file=%{edits_yaml} %s
+// POINTER_TO_ARRAY: Replacements: []
+// RUN: FileCheck --check-prefix=POINTER_TO_ARRAY_REPORT 
--input-file=%{report_sarif} %s
+// POINTER_TO_ARRAY_REPORT: "text": "pointer to array is not yet rewritten"
+
+
+//--- reference_to_pointer.cpp
+void use(int *&p) {
+  p[5] = 0;
+}
+
+//--- reference_to_pointer.directives
+// REDEFINE: %{testname} = reference_to_pointer
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=REFERENCE_TO_POINTER 
--input-file=%{edits_yaml} %s
+// REFERENCE_TO_POINTER: Replacements: []
+// RUN: FileCheck --check-prefix=REFERENCE_TO_POINTER_REPORT 
--input-file=%{report_sarif} %s
+// REFERENCE_TO_POINTER_REPORT: "text": "reference to pointer is not yet 
rewritten"
+
+
+//--- pointer_parenthesized_declarator.cpp
+void use() {
+  int v = 0;
+  int (*p) = &v;
+  (void)p[5];
+}
+
+//--- pointer_parenthesized_declarator.directives
+// REDEFINE: %{testname} = pointer_parenthesized_declarator
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=POINTER_PARENTHESIZED 
--input-file=%{edits_yaml} %s
+// POINTER_PARENTHESIZED: Replacements: []
+// RUN: FileCheck --check-prefix=POINTER_PARENTHESIZED_REPORT 
--input-file=%{report_sarif} %s
+// POINTER_PARENTHESIZED_REPORT: "text": "pointer declarator does not end at 
its '*'"
+
+
+//--- field_pointer.cpp
+struct S{int *p;};
+void use(S *w) {
+  w->p[5] = 0;
+}
+
+//--- field_pointer.directives
+// REDEFINE: %{testname} = field_pointer
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=FIELD_POINTER --input-file=%{edits_yaml} %s
+// FIELD_POINTER: Offset: 9
+// FIELD_POINTER: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=FIELD_POINTER_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// FIELD_POINTER_APPLIED: struct S{bounded_ptr<int> p;};
+
+
+//--- field_array.cpp
+// An array-typed struct field.
+struct S{int arr[3];};
+void use(S *w) {
+  w->arr[5] = 0;
+}
+
+//--- field_array.directives
+// REDEFINE: %{testname} = field_array
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=FIELD_ARRAY --input-file=%{edits_yaml} %s
+// FIELD_ARRAY: Offset: 41
+// FIELD_ARRAY: ReplacementText: 'bounded_array<int, 3>'
+// FIELD_ARRAY: Offset: 48
+// FIELD_ARRAY: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=FIELD_ARRAY_APPLIED --input-file=%t/%{testname}.cpp %s %}
+// FIELD_ARRAY_APPLIED: struct S{bounded_array<int, 3> arr;};
+
+
+// ============================================================================
+// Macros
+// ============================================================================
+
+//--- macro_expansion.cpp
+// Skip MacroExpansion: the declarator's type is spelled through a macro.
+#define PTR int *
+void use(PTR p) {
+  p[5] = 0;
+}
+
+//--- macro_expansion.directives
+// REDEFINE: %{testname} = macro_expansion
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=MACRO_EXPANSION --input-file=%{edits_yaml} %s
+// MACRO_EXPANSION: Replacements: []
+// RUN: FileCheck --check-prefix=MACRO_EXPANSION_REPORT 
--input-file=%{report_sarif} %s
+// MACRO_EXPANSION_REPORT: "text": "declarator spelled through a macro is not 
yet rewritten"
+
+
+// ============================================================================
+// Typedefs
+// ============================================================================
+
+//--- typedef_array_of_function_pointers.cpp
+// A typedef used as an array element type does not block the array rewrite:
+// the typedef keeps the declarator a clean prefix + [N] suffix, so only the
+// (unexpanded) element spelling changes.
+typedef void (*FP)();
+void use() {
+  FP arr[4];
+  arr[5]();
+}
+
+//--- typedef_array_of_function_pointers.directives
+// REDEFINE: %{testname} = typedef_array_of_function_pointers
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=TYPEDEF_ARRAY_OF_FNPTRS 
--input-file=%{edits_yaml} %s
+// TYPEDEF_ARRAY_OF_FNPTRS: Offset: 233
+// TYPEDEF_ARRAY_OF_FNPTRS: ReplacementText: 'bounded_array<FP, 4>'
+// TYPEDEF_ARRAY_OF_FNPTRS: Offset: 239
+// TYPEDEF_ARRAY_OF_FNPTRS: ReplacementText: ''
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=TYPEDEF_ARRAY_OF_FNPTRS_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// TYPEDEF_ARRAY_OF_FNPTRS_APPLIED: bounded_array<FP, 4> arr;
+
+
+//--- typedef_pointer.cpp
+typedef int *P;
+void use(P p) {
+  p[5] = 0;
+}
+
+//--- typedef_pointer.directives
+// REDEFINE: %{testname} = typedef_pointer
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=TYPEDEF_POINTER --input-file=%{edits_yaml} %s
+// TYPEDEF_POINTER: Replacements: []
+// RUN: FileCheck --check-prefix=TYPEDEF_POINTER_REPORT 
--input-file=%{report_sarif} %s
+// TYPEDEF_POINTER_REPORT: "text": "no TypeLoc for the pointee or array 
element type"
+
+
+//--- unnamable_anonymous_struct.cpp
+struct { int x; } *p;
+void use(int i) {
+  p[i].x = 0;
+}
+
+//--- unnamable_anonymous_struct.directives
+// REDEFINE: %{testname} = unnamable_anonymous_struct
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=UNNAMABLE_ANON_STRUCT 
--input-file=%{edits_yaml} %s
+// UNNAMABLE_ANON_STRUCT: Replacements: []
+// RUN: FileCheck --check-prefix=UNNAMABLE_ANON_STRUCT_REPORT 
--input-file=%{report_sarif} %s
+// UNNAMABLE_ANON_STRUCT_REPORT: "text": "the pointee or array element type 
has no name that can be written as a template argument"
+
+
+//--- unnamable_lambda_decltype.cpp
+void use() {
+  auto f = [](int x) { return x; };
+  decltype(f) *p = &f;
+  (void)p[5];
+}
+
+//--- unnamable_lambda_decltype.directives
+// REDEFINE: %{testname} = unnamable_lambda_decltype
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=UNNAMABLE_LAMBDA --input-file=%{edits_yaml} %s
+// UNNAMABLE_LAMBDA: Replacements: []
+// RUN: FileCheck --check-prefix=UNNAMABLE_LAMBDA_REPORT 
--input-file=%{report_sarif} %s
+// UNNAMABLE_LAMBDA_REPORT: "text": "the pointee or array element type has no 
name that can be written as a template argument"
+
+
+//--- whitespace_free_pointer.cpp
+int*p;
+void use(){p[5]=0;}
+
+//--- whitespace_free_pointer.directives
+// REDEFINE: %{testname} = whitespace_free_pointer
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=WHITESPACE_FREE_POINTER 
--input-file=%{edits_yaml} %s
+// WHITESPACE_FREE_POINTER: Offset: 0
+// WHITESPACE_FREE_POINTER: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=WHITESPACE_FREE_POINTER_APPLIED --input-file=%t/%{testname}.cpp 
%s %}
+// WHITESPACE_FREE_POINTER_APPLIED: bounded_ptr<int> p;
+
+
+//--- skip_declaration_group.cpp
+void use() {
+  int *a, *b;
+  a[5] = 0;
+  b[5] = 0;
+}
+
+//--- skip_declaration_group.directives
+// REDEFINE: %{testname} = skip_declaration_group
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=SKIP_DECL_GROUP --input-file=%{edits_yaml} %s
+// SKIP_DECL_GROUP: Replacements: []
+// RUN: FileCheck --check-prefix=SKIP_DECL_GROUP_REPORT 
--input-file=%{report_sarif} %s
+// SKIP_DECL_GROUP_REPORT-DAG: "text": "declarator of a multi-declarator group 
is not yet rewritten"
+
+
+//--- skip_trailing_return_type.cpp
+auto f(int *p) -> int * {
+  return p;
+}
+void use() {
+  int *q = f(nullptr);
+  q[5] = 0;
+}
+
+//--- skip_trailing_return_type.directives
+// REDEFINE: %{testname} = skip_trailing_return_type
+// RUN: %{extract}
+// RUN: %{link}
+// RUN: %{analyze}
+// RUN: %{transform}
+// RUN: FileCheck --check-prefix=SKIP_TRAILING_RETURN_REPORT 
--input-file=%{report_sarif} %s
+// SKIP_TRAILING_RETURN_REPORT: "text": "trailing return type is not yet 
rewritten"
+// RUN: FileCheck --check-prefix=SKIP_TRAILING_RETURN 
--input-file=%{edits_yaml} %s
+// SKIP_TRAILING_RETURN: Offset: 7
+// SKIP_TRAILING_RETURN: ReplacementText: 'bounded_ptr<int> '
+// SKIP_TRAILING_RETURN: Offset: 55
+// SKIP_TRAILING_RETURN: ReplacementText: 'bounded_ptr<int> '
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck 
--check-prefix=SKIP_TRAILING_RETURN_APPLIED --input-file=%t/%{testname}.cpp %s 
%}
+// SKIP_TRAILING_RETURN_APPLIED: auto f(bounded_ptr<int> p) -> int * {
+// SKIP_TRAILING_RETURN_APPLIED: bounded_ptr<int> q = f(nullptr);
diff --git 
a/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp 
b/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp
new file mode 100644
index 0000000000000..b366c3741a356
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/source-edit-generation/multi-tu-edits-merge.cpp
@@ -0,0 +1,208 @@
+// Tests clang-ssaf-src-edit-merge against real multi-TU source.
+// Specifically, this file tests non-conflicting merges across multiple TUs.
+
+// UNSUPPORTED: target={{.*}}
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// DEFINE: %{casedir} = unset
+// DEFINE: %{testname} = unset
+// DEFINE: %{tu_json} = %{casedir}/%{testname}.tu.json
+// DEFINE: %{lu_json} = %{casedir}/%{testname}.lu.json
+// DEFINE: %{wpa_json} = %{casedir}/%{testname}.wpa.json
+// DEFINE: %{apply_dir} = %{casedir}/%{testname}_apply
+// DEFINE: %{edits_yaml} = %{apply_dir}/%{testname}.edits.yaml
+// DEFINE: %{extract} = %clang -fsyntax-only %{casedir}/%{testname}.cpp \
+// DEFINE:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
+// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu 
--ssaf-tu-summary-file=%{tu_json}
+// DEFINE: %{link} = clang-ssaf-linker %{tu_json} -o %{lu_json}
+// DEFINE: %{analyze} = clang-ssaf-analyzer %{lu_json} -o %{wpa_json} -a 
UnsafeBufferReachableAnalysisResult
+// DEFINE: %{transform} = mkdir -p %{apply_dir} && %clang -fsyntax-only 
%{casedir}/%{testname}.cpp \
+// DEFINE:   --ssaf-source-transformation=cpp-bounded-buffers \
+// DEFINE:   --ssaf-global-scope-analysis-result=%{wpa_json} \
+// DEFINE:   --ssaf-src-edit-file=%{edits_yaml} \
+// DEFINE:   
--ssaf-transformation-report-file=%{casedir}/%{testname}.report.sarif \
+// DEFINE:   --ssaf-compilation-unit-id=%{testname}.cu 
--ssaf-link-unit-id=%{testname}.lu
+// DEFINE: %{pipeline} = %{extract} && %{link} && %{analyze} && %{transform}
+// DEFINE: %{merge_inputs} = unset
+// DEFINE: %{merge} = mkdir -p %{casedir}/merge_apply && 
clang-ssaf-src-edit-merge %{merge_inputs} -o %{casedir}/merge_apply/merged.yaml 
--sarif-conflicts-out=%{casedir}/conflicts.sarif 2> %{casedir}/merge.stderr
+// DEFINE: %{apply} = clang-apply-replacements %{casedir}/merge_apply
+
+//--- distinct-files/a.h
+int *ga;
+
+//--- distinct-files/b.h
+int *gb;
+
+//--- distinct-files/a.cpp
+#include "a.h"
+void use_a() { ga[5] = 0; }
+
+//--- distinct-files/b.cpp
+#include "b.h"
+void use_b() { gb[7] = 0; }
+
+// REDEFINE: %{casedir} = %t/distinct-files
+// REDEFINE: %{testname} = a
+// RUN: %{pipeline}
+// REDEFINE: %{testname} = b
+// RUN: %{pipeline}
+
+// REDEFINE: %{merge_inputs} = %t/distinct-files/a_apply/a.edits.yaml 
%t/distinct-files/b_apply/b.edits.yaml
+// RUN: %{merge}
+
+// Both survive, different files:
+// RUN: FileCheck --check-prefix=DF_MERGED 
--input-file=%t/distinct-files/merge_apply/merged.yaml %s
+// DF_MERGED: FilePath:
+// DF_MERGED-SAME: a.h
+// DF_MERGED: FilePath:
+// DF_MERGED-SAME: b.h
+
+// RUN: FileCheck --check-prefix=DF_NOSTDERR 
--input-file=%t/distinct-files/merge.stderr --allow-empty %s
+// DF_NOSTDERR-NOT: conflict:
+
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DF_A_APPLIED 
--input-file=%t/distinct-files/a.h %s %}
+// DF_A_APPLIED: bounded_ptr<int> ga;
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DF_B_APPLIED 
--input-file=%t/distinct-files/b.h %s %}
+// DF_B_APPLIED: bounded_ptr<int> gb;
+
+
+//--- distinct-locations/shared.h
+int *g1;
+int *g2;
+
+//--- distinct-locations/a.cpp
+#include "shared.h"
+void use_a() { g1[5] = 0; }
+
+//--- distinct-locations/b.cpp
+#include "shared.h"
+void use_b() { g2[7] = 0; }
+
+// REDEFINE: %{casedir} = %t/distinct-locations
+// REDEFINE: %{testname} = a
+// RUN: %{pipeline}
+// REDEFINE: %{testname} = b
+// RUN: %{pipeline}
+
+// REDEFINE: %{merge_inputs} = %t/distinct-locations/a_apply/a.edits.yaml 
%t/distinct-locations/b_apply/b.edits.yaml
+// RUN: %{merge}
+
+// Both survive, same file, distinct offsets:
+// RUN: FileCheck --check-prefix=DL_MERGED 
--input-file=%t/distinct-locations/merge_apply/merged.yaml %s
+// DL_MERGED: Offset:          0
+// DL_MERGED-NEXT: Length:          5
+// DL_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
+// DL_MERGED: Offset:          9
+// DL_MERGED-NEXT: Length:          5
+// DL_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
+
+// RUN: FileCheck --check-prefix=DL_NOSTDERR 
--input-file=%t/distinct-locations/merge.stderr --allow-empty %s
+// DL_NOSTDERR-NOT: conflict:
+
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=DL_APPLIED 
--input-file=%t/distinct-locations/shared.h %s %}
+// DL_APPLIED: bounded_ptr<int> g1;
+// DL_APPLIED-NEXT: bounded_ptr<int> g2;
+
+
+//--- three-tu-distinct/shared.h
+int *g1;int *g2;int *g3;
+
+//--- three-tu-distinct/a.cpp
+#include "shared.h"
+void use_a() { g1[5] = 0; }
+
+//--- three-tu-distinct/b.cpp
+#include "shared.h"
+void use_b() { g2[7] = 0; }
+
+//--- three-tu-distinct/c.cpp
+#include "shared.h"
+void use_c() { g3[9] = 0; }
+
+// REDEFINE: %{casedir} = %t/three-tu-distinct
+// REDEFINE: %{testname} = a
+// RUN: %{pipeline}
+// REDEFINE: %{testname} = b
+// RUN: %{pipeline}
+// REDEFINE: %{testname} = c
+// RUN: %{pipeline}
+
+// REDEFINE: %{merge_inputs} = %t/three-tu-distinct/a_apply/a.edits.yaml 
%t/three-tu-distinct/b_apply/b.edits.yaml 
%t/three-tu-distinct/c_apply/c.edits.yaml
+// RUN: %{merge}
+
+// All three survive:
+// RUN: FileCheck --check-prefix=TTD_MERGED 
--input-file=%t/three-tu-distinct/merge_apply/merged.yaml %s
+// TTD_MERGED: Offset:          0
+// TTD_MERGED: Offset:          8
+// TTD_MERGED: Offset:          16
+
+// RUN: FileCheck --check-prefix=TTD_NOSTDERR 
--input-file=%t/three-tu-distinct/merge.stderr --allow-empty %s
+// TTD_NOSTDERR-NOT: conflict:
+
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=TTD_APPLIED 
--input-file=%t/three-tu-distinct/shared.h %s %}
+// TTD_APPLIED: bounded_ptr<int> g1;bounded_ptr<int> g2;bounded_ptr<int> g3;
+
+
+//--- static-inline-fun-dedup/shared.h
+static inline int * foo(int *p) {
+  return p;
+}
+
+//--- static-inline-fun-dedup/a.cpp
+#include "shared.h"
+void caller(int * p) { int * q = foo(p); q[5] = 0; }
+
+//--- static-inline-fun-dedup/b.cpp
+#include "shared.h"
+void caller(int * p) { int * q = foo(p); q[5] = 0; }
+
+// REDEFINE: %{casedir} = %t/static-inline-fun-dedup
+// REDEFINE: %{testname} = a
+// RUN: %{pipeline}
+// REDEFINE: %{testname} = b
+// RUN: %{pipeline}
+
+// REDEFINE: %{merge_inputs} = %t/static-inline-fun-dedup/a_apply/a.edits.yaml 
%t/static-inline-fun-dedup/b_apply/b.edits.yaml
+// RUN: %{merge}
+
+// Shared static-linkage function's rewrite dedups; each caller's own file
+// still survives on its own:
+// RUN: FileCheck --check-prefix=SIF_MERGED 
--input-file=%t/static-inline-fun-dedup/merge_apply/merged.yaml %s
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: a.cpp
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: a.cpp
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: b.cpp
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: b.cpp
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: shared.h
+// SIF_MERGED-NEXT: Offset:          14
+// SIF_MERGED-NEXT: Length:          5
+// SIF_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
+// SIF_MERGED: FilePath:
+// SIF_MERGED-SAME: shared.h
+// SIF_MERGED-NEXT: Offset:          24
+// SIF_MERGED-NEXT: Length:          5
+// SIF_MERGED-NEXT: ReplacementText: 'bounded_ptr<int> '
+// SIF_MERGED-NOT: FilePath:
+
+// RUN: FileCheck --check-prefix=SIF_NOSTDERR 
--input-file=%t/static-inline-fun-dedup/merge.stderr --allow-empty %s
+// SIF_NOSTDERR-NOT: conflict:
+
+// RUN: %if clang-apply-replacements %{ %{apply} %}
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_H_APPLIED 
--input-file=%t/static-inline-fun-dedup/shared.h %s %}
+// SIF_H_APPLIED: static inline bounded_ptr<int> foo(bounded_ptr<int> p) {
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_A_APPLIED 
--input-file=%t/static-inline-fun-dedup/a.cpp %s %}
+// SIF_A_APPLIED: void caller(bounded_ptr<int> p) { bounded_ptr<int> q = 
foo(p); q[5] = 0; }
+// RUN: %if clang-apply-replacements %{ FileCheck --check-prefix=SIF_B_APPLIED 
--input-file=%t/static-inline-fun-dedup/b.cpp %s %}
+// SIF_B_APPLIED: void caller(bounded_ptr<int> p) { bounded_ptr<int> q = 
foo(p); q[5] = 0; }
+
+
+

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

Reply via email to