https://github.com/steakhal updated 
https://github.com/llvm/llvm-project/pull/186447

From efd45080697d53d287966048c24091f38e3729ea Mon Sep 17 00:00:00 2001
From: Balazs Benics <[email protected]>
Date: Fri, 13 Mar 2026 13:21:47 +0000
Subject: [PATCH 1/3] [analyzer][NFC] Reorg and add clang::suppress tests

Assisted-by: claude
---
 .../class-template-specializations.cpp        | 348 +++++++++++++++++
 .../test/Analysis/clang-suppress/classes.cpp  |  75 ++++
 .../clang-suppress/diagnostic-identifiers.cpp | 115 ++++++
 .../test/Analysis/clang-suppress/friends.cpp  | 366 ++++++++++++++++++
 .../clang-suppress/function-templates.cpp     |  93 +++++
 .../test/Analysis/clang-suppress/lambdas.cpp  | 238 ++++++++++++
 clang/test/Analysis/clang-suppress/macros.cpp | 186 +++++++++
 .../Analysis/clang-suppress/namespaces.cpp    |  35 ++
 .../Analysis/clang-suppress/statements.cpp    | 158 ++++++++
 .../clang-suppress/template-methods.cpp       | 132 +++++++
 clang/test/Analysis/suppression-attr.cpp      |  91 -----
 11 files changed, 1746 insertions(+), 91 deletions(-)
 create mode 100644 
clang/test/Analysis/clang-suppress/class-template-specializations.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/classes.cpp
 create mode 100644 
clang/test/Analysis/clang-suppress/diagnostic-identifiers.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/friends.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/function-templates.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/lambdas.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/macros.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/namespaces.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/statements.cpp
 create mode 100644 clang/test/Analysis/clang-suppress/template-methods.cpp
 delete mode 100644 clang/test/Analysis/suppression-attr.cpp

diff --git 
a/clang/test/Analysis/clang-suppress/class-template-specializations.cpp 
b/clang/test/Analysis/clang-suppress/class-template-specializations.cpp
new file mode 100644
index 0000000000000..1d1202ca70ff7
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/class-template-specializations.cpp
@@ -0,0 +1,348 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// ============================================================================
+// Group A: Basic class template — attribute on primary
+// ============================================================================
+
+// Placeholder types for triggering instantiations.
+// - Type{A,B} should match an unconstrained template type parameter.
+// - Specialized{A,B} should match some specialization pattern.
+struct TypeA{};
+struct TypeB{};
+struct SpecializedA{};
+struct SpecializedB{};
+
+template <typename T>
+class [[clang::suppress]] A_Primary {
+public:
+  void inline_method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  void outline_method();
+  static void static_inline() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  static void static_outline();
+};
+
+template <typename T>
+void A_Primary<T>::outline_method() {
+  // Out-of-line: lexical context is namespace.
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+template <typename T>
+void A_Primary<T>::static_outline() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void test_A() {
+  A_Primary<TypeA>().inline_method();
+  A_Primary<TypeA>().outline_method();
+  A_Primary<TypeA>::static_inline();
+  A_Primary<TypeA>::static_outline();
+  // Different instantiation.
+  A_Primary<TypeB>().inline_method();
+}
+
+// ============================================================================
+// Group B: Explicit full specialization — attribute isolation
+// ============================================================================
+
+// --- B1: attribute on primary only ---
+
+template <typename T>
+class [[clang::suppress]] B1_AttrOnPrimary {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+// Explicit specialization is independent — NOT suppressed.
+template <>
+struct B1_AttrOnPrimary<SpecializedA> {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_B1() {
+  B1_AttrOnPrimary<TypeA>().method();           // suppressed (primary)
+  B1_AttrOnPrimary<SpecializedA>().method();    // warns (spec, no attr)
+}
+
+// --- B2: attribute on specialization only ---
+
+template <typename T>
+struct B2_AttrOnSpec {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+template <>
+class [[clang::suppress]] B2_AttrOnSpec<SpecializedA> {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+void test_B2() {
+  B2_AttrOnSpec<TypeA>().method();              // warns (primary, no attr)
+  B2_AttrOnSpec<SpecializedA>().method();       // suppressed (spec has attr)
+}
+
+// --- B3: attribute on both primary and specialization ---
+
+template <typename T>
+class [[clang::suppress]] B3_AttrOnBoth {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+template <>
+class [[clang::suppress]] B3_AttrOnBoth<SpecializedA> {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+void test_B3() {
+  B3_AttrOnBoth<TypeA>().method();              // suppressed
+  B3_AttrOnBoth<SpecializedA>().method();       // suppressed
+}
+
+// ============================================================================
+// Group C: Partial specializations
+// ============================================================================
+
+// --- C1: attribute on partial specialization only ---
+
+template <typename T, typename U>
+struct C1_AttrOnPartial {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+template <typename T>
+class [[clang::suppress]] C1_AttrOnPartial<T, SpecializedA> {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+void test_C1() {
+  C1_AttrOnPartial<TypeA, TypeA>().method();            // warns (primary, no 
attr)
+  C1_AttrOnPartial<TypeA, SpecializedA>().method();     // suppressed (partial 
spec)
+}
+
+// --- C2: attribute on primary, partial spec has none ---
+
+template <typename T, typename U>
+class [[clang::suppress]] C2_AttrOnPrimary {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+template <typename T>
+struct C2_AttrOnPrimary<T, SpecializedA> {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_C2() {
+  C2_AttrOnPrimary<TypeA, TypeA>().method();            // suppressed (primary)
+  C2_AttrOnPrimary<TypeA, SpecializedA>().method();     // warns (partial 
spec, no attr)
+}
+
+// --- C3: two partial specializations, only one suppressed ---
+
+template <typename T, typename U>
+struct C3_TwoPartials {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+template <typename T>
+class [[clang::suppress]] C3_TwoPartials<T, SpecializedA> {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+template <typename T>
+struct C3_TwoPartials<T, SpecializedB> {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_C3() {
+  C3_TwoPartials<TypeA, TypeA>().method();              // warns (primary)
+  C3_TwoPartials<TypeA, SpecializedA>().method();       // suppressed (first 
partial)
+  C3_TwoPartials<TypeA, SpecializedB>().method();       // warns (second 
partial, no attr)
+}
+
+// ============================================================================
+// Group D: Forward-declared class template (chooseDefinitionRedecl path)
+// ============================================================================
+
+// The template is forward-declared, then defined. chooseDefinitionRedecl()
+// must find the definition among the redeclarations.
+
+// --- D1: Forward-declared without attribute, defined with attribute ---
+template <typename T>
+class D1_ForwardDeclared;
+
+template <typename T>
+class [[clang::suppress]] D1_ForwardDeclared {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+void test_D1() {
+  D1_ForwardDeclared<TypeA>().method();
+}
+
+// --- D2: Forward-declared without attribute, defined without attribute ---
+template <typename T>
+struct D2_ForwardDeclared_NoAttr;
+
+template <typename T>
+struct D2_ForwardDeclared_NoAttr {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_D2() {
+  D2_ForwardDeclared_NoAttr<TypeA>().method();
+}
+
+// ============================================================================
+// Group E: Specialization with out-of-line (OOL) methods
+// ============================================================================
+
+template <typename T>
+class [[clang::suppress]] E_SpecWithOOL {
+public:
+  void inline_method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  void outline_method();
+};
+
+template <typename T>
+void E_SpecWithOOL<T>::outline_method() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+// Explicit specialization with attribute and out-of-line method.
+template <>
+class [[clang::suppress]] E_SpecWithOOL<SpecializedA> {
+public:
+  void inline_method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  void outline_method();
+};
+
+// Out-of-line for the specialization — not suppressed.
+void E_SpecWithOOL<SpecializedA>::outline_method() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void test_E() {
+  E_SpecWithOOL<TypeA>().inline_method();
+  E_SpecWithOOL<TypeA>().outline_method();
+  E_SpecWithOOL<SpecializedA>().inline_method();
+  E_SpecWithOOL<SpecializedA>().outline_method();
+}
+
+// ============================================================================
+// Group F: Nested class inside class template specialization
+// ============================================================================
+
+template <typename T>
+class [[clang::suppress]] F_Outer {
+public:
+  struct Inner {
+    void method() {
+      clang_analyzer_warnIfReached(); // no-warning
+    }
+  };
+};
+
+template <typename T>
+struct F_Outer_NoAttr {
+  struct Inner {
+    void method() {
+      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    }
+  };
+};
+
+void test_F() {
+  F_Outer<TypeA>::Inner().method();
+  F_Outer_NoAttr<TypeA>::Inner().method();
+}
+
+// ============================================================================
+// Group G: Class template with default template arguments
+// ============================================================================
+
+template <typename T, typename U = TypeA>
+class [[clang::suppress]] G_WithDefault {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+template <typename T, typename U = TypeA>
+struct G_WithDefault_NoAttr {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_G() {
+  G_WithDefault<TypeA>().method();               // uses default U=TypeA
+  G_WithDefault<TypeA, TypeB>().method();        // explicit U=TypeB
+  G_WithDefault_NoAttr<TypeA>().method();        // uses default U=TypeA
+}
+
+// ============================================================================
+// Group H: Explicit instantiation directive
+// ============================================================================
+
+template <typename T>
+class [[clang::suppress]] H_ExplicitInst {
+public:
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+// Explicit instantiation.
+template class H_ExplicitInst<SpecializedA>;
+
+void test_H() {
+  H_ExplicitInst<SpecializedA>().method();
+}
diff --git a/clang/test/Analysis/clang-suppress/classes.cpp 
b/clang/test/Analysis/clang-suppress/classes.cpp
new file mode 100644
index 0000000000000..4c285880c86ea
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/classes.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] on non-template classes and 
methods.
+
+// ============================================================================
+// Group A: Attribute on class — inline method suppressed, out-of-line not
+// ============================================================================
+
+// Placeholder type for triggering instantiations.
+struct Type{};
+
+class [[clang::suppress]] SuppressedClass {
+  void foo() {
+    clang_analyzer_warnIfReached(); // no-warning: inline method in suppressed 
class
+  }
+
+  void bar();
+};
+
+void SuppressedClass::bar() {
+  clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+// ============================================================================
+// Group B: Attribute on method declaration vs definition
+// ============================================================================
+
+class SuppressedMethodClass {
+  // Attribute on the inline definition — suppressed.
+  [[clang::suppress]] void foo() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+
+  // Attribute on the in-class declaration only — NOT honored at out-of-line 
def.
+  [[clang::suppress]] void bar1();
+
+  // No attribute on the in-class declaration.
+  void bar2();
+};
+
+void SuppressedMethodClass::bar1() {
+  clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+// Attribute on the out-of-line definition — suppressed.
+[[clang::suppress]]
+void SuppressedMethodClass::bar2() {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+// ============================================================================
+// Group C: Template member function with early instantiation
+// ============================================================================
+
+// The suppression mechanism walks the lexical DeclContext chain to find
+// suppression attributes. This test verifies that the walk follows template
+// instantiation patterns (not just primary templates) when the instantiation
+// point precedes the definition.
+
+struct Clazz {
+  template <typename T>
+  static void templated_memfn();
+};
+
+// This must come before the 'templated_memfn' is defined!
+void instantiate() {
+  Clazz::templated_memfn<Type>();
+}
+
+template <typename T>
+void Clazz::templated_memfn() {
+  [[clang::suppress]] clang_analyzer_warnIfReached(); // no-warning
+}
diff --git a/clang/test/Analysis/clang-suppress/diagnostic-identifiers.cpp 
b/clang/test/Analysis/clang-suppress/diagnostic-identifiers.cpp
new file mode 100644
index 0000000000000..293f6fe12021c
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/diagnostic-identifiers.cpp
@@ -0,0 +1,115 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Tests for [[clang::suppress]] with diagnostic identifier arguments.
+
+// ============================================================================
+// Group A: Bare [[clang::suppress]] vs. with identifier
+// ============================================================================
+
+void bare_suppress() {
+  [[clang::suppress]] {
+    clang_analyzer_warnIfReached(); // no-warning: bare suppress works
+  }
+}
+
+void suppress_with_identifier() {
+  // FIXME: This should suppress debug.ExprInspection warnings, but currently
+  // any identifier makes the suppression a no-op.
+  [[clang::suppress("debug.ExprInspection")]] {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+void suppress_with_wrong_identifier() {
+  // Even with the wrong checker name, the current behavior is the same:
+  // any identifier makes the suppression a no-op.
+  [[clang::suppress("alpha.SomeOtherChecker")]] {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group B: Identifier on declarations
+// ============================================================================
+
+[[clang::suppress]] void decl_bare_suppress() {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+// FIXME: Should suppress, but currently identifiers disable suppression.
+[[clang::suppress("debug.ExprInspection")]] void decl_with_identifier() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group C: Identifier on class
+// ============================================================================
+
+struct [[clang::suppress]] C_BareSuppressedClass {
+  void method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+// FIXME: Should suppress, but identifiers disable suppression.
+struct [[clang::suppress("core")]] C_IdentifierSuppressedClass {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+// ============================================================================
+// Group D: Multiple identifiers
+// ============================================================================
+
+void multiple_identifiers() {
+  // FIXME: Multiple identifiers — currently treated as a no-op.
+  [[clang::suppress("core.NullDereference", "core.DivideZero")]] {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group E: Empty string identifier
+// ============================================================================
+
+void empty_string_identifier() {
+  // An empty string is still a non-empty identifier list.
+  [[clang::suppress("")]] {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group F: Mixed — bare suppress and identifier suppress in same function
+// ============================================================================
+
+void mixed_suppressions() {
+  [[clang::suppress]] {
+    clang_analyzer_warnIfReached(); // no-warning: bare suppress works
+  }
+
+  // FIXME: Should suppress too, but identifiers disable it.
+  [[clang::suppress("debug.ExprInspection")]] {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group G: Identifier on namespace
+// ============================================================================
+
+namespace [[clang::suppress]] G_BareNS {
+  void func() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+} // namespace G_BareNS
+
+// FIXME: Should suppress, but identifiers disable it.
+namespace [[clang::suppress("core")]] G_IdentifierNS {
+  void func() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+} // namespace G_IdentifierNS
diff --git a/clang/test/Analysis/clang-suppress/friends.cpp 
b/clang/test/Analysis/clang-suppress/friends.cpp
new file mode 100644
index 0000000000000..430699aa2d8b2
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/friends.cpp
@@ -0,0 +1,366 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] on classes with friend 
declarations.
+//
+// Pruned matrix of valid combinations:
+//   Axis 1: fwd-decl at namespace scope (yes / no)
+//   Axis 2: body location (inline / out-of-line)
+//   Axis 3: template (yes / no)
+//
+// Each case has a suppressed variant (class has [[clang::suppress]])
+// and an unsuppressed variant (class without it).
+
+// Placeholder types for triggering instantiations.
+// - Type{A,B} should match an unconstrained template type parameter.
+// - Specialized should match some specialization pattern.
+struct TypeA{};
+struct TypeB{};
+struct Specialized{};
+
+// ============================================================================
+// Group A: Non-template friend functions
+// ============================================================================
+
+// --- A1: no fwd-decl, inline body ---
+
+struct [[clang::suppress]] A1_Suppressed {
+  friend void a1_suppressed(A1_Suppressed) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+struct A1_Unsuppressed {
+  friend void a1_unsuppressed(A1_Unsuppressed) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_A1() {
+  a1_suppressed(A1_Suppressed{});
+  a1_unsuppressed(A1_Unsuppressed{});
+}
+
+// --- A2: no fwd-decl, out-of-line body ---
+
+struct [[clang::suppress]] A2_Suppressed {
+  friend void a2_suppressed(A2_Suppressed);
+};
+void a2_suppressed(A2_Suppressed) {
+  // Out-of-line: lexical parent is the namespace, NOT the class.
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+struct A2_Unsuppressed {
+  friend void a2_unsuppressed(A2_Unsuppressed);
+};
+void a2_unsuppressed(A2_Unsuppressed) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void test_A2() {
+  a2_suppressed(A2_Suppressed{});
+  a2_unsuppressed(A2_Unsuppressed{});
+}
+
+// --- A3: fwd-decl, inline body ---
+
+extern void a3_suppressed();
+struct [[clang::suppress]] A3_Suppressed {
+  friend void a3_suppressed() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+extern void a3_unsuppressed();
+struct A3_Unsuppressed {
+  friend void a3_unsuppressed() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_A3() {
+  a3_suppressed();
+  a3_unsuppressed();
+}
+
+// --- A4: fwd-decl, out-of-line body ---
+
+extern void a4_suppressed();
+struct [[clang::suppress]] A4_Suppressed {
+  friend void a4_suppressed();
+};
+void a4_suppressed() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+extern void a4_unsuppressed();
+struct A4_Unsuppressed {
+  friend void a4_unsuppressed();
+};
+void a4_unsuppressed() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void test_A4() {
+  a4_suppressed();
+  a4_unsuppressed();
+}
+
+// ============================================================================
+// Group B: Friend function templates (primary template)
+// ============================================================================
+
+// --- B1: no fwd-decl, inline body ---
+
+struct [[clang::suppress]] B1_Suppressed {
+  template <typename T>
+  friend void b1_suppressed(B1_Suppressed, T) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+struct B1_Unsuppressed {
+  template <typename T>
+  friend void b1_unsuppressed(B1_Unsuppressed, T) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_B1() {
+  b1_suppressed(B1_Suppressed{}, TypeA{});
+  b1_unsuppressed(B1_Unsuppressed{}, TypeA{});
+}
+
+// --- B2: no fwd-decl, out-of-line body ---
+
+struct [[clang::suppress]] B2_Suppressed {
+  template <typename T>
+  friend void b2_suppressed(B2_Suppressed, T);
+};
+template <typename T>
+void b2_suppressed(B2_Suppressed, T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+struct B2_Unsuppressed {
+  template <typename T>
+  friend void b2_unsuppressed(B2_Unsuppressed, T);
+};
+template <typename T>
+void b2_unsuppressed(B2_Unsuppressed, T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void test_B2() {
+  b2_suppressed(B2_Suppressed{}, TypeA{});
+  b2_unsuppressed(B2_Unsuppressed{}, TypeA{});
+}
+
+// --- B3: fwd-decl, inline body ---
+
+template <typename T>
+extern void b3_suppressed(T);
+struct [[clang::suppress]] B3_Suppressed {
+  template <typename T>
+  friend void b3_suppressed(T) {
+    // FIXME: This should be suppressed.
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+template <typename T>
+extern void b3_unsuppressed(T);
+struct B3_Unsuppressed {
+  template <typename T>
+  friend void b3_unsuppressed(T) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_B3() {
+  b3_suppressed(TypeA{});
+  b3_unsuppressed(TypeA{});
+}
+
+// --- B4: fwd-decl, out-of-line body ---
+
+template <typename T>
+extern void b4_suppressed(T);
+struct [[clang::suppress]] B4_Suppressed {
+  template <typename T>
+  friend void b4_suppressed(T);
+};
+template <typename T>
+void b4_suppressed(T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+template <typename T>
+extern void b4_unsuppressed(T);
+struct B4_Unsuppressed {
+  template <typename T>
+  friend void b4_unsuppressed(T);
+};
+template <typename T>
+void b4_unsuppressed(T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void test_B4() {
+  b4_suppressed(TypeA{});
+  b4_unsuppressed(TypeA{});
+}
+
+// ============================================================================
+// Group C: Friend function template explicit specializations
+// ============================================================================
+
+// --- C1: primary inline in suppressed class, explicit spec defined 
out-of-line ---
+// The explicit specialization is NOT defined inside the class, so it should
+// NOT be suppressed.
+
+struct [[clang::suppress]] C1_Suppressed {
+  template <typename T>
+  friend void c1_suppressed(C1_Suppressed, T) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+template <>
+void c1_suppressed(C1_Suppressed, Specialized) {
+  // Explicit specialization defined outside the class — not suppressed.
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void test_C1() {
+  c1_suppressed(C1_Suppressed{}, TypeA{});         // uses primary (suppressed)
+  c1_suppressed(C1_Suppressed{}, Specialized{});   // uses explicit spec (not 
suppressed)
+}
+
+// ============================================================================
+// Group D: Friend classes (declared, not defined inline — C++ forbids
+// defining a type in a friend declaration)
+// ============================================================================
+
+// --- D1: friend class only declared, defined outside ---
+
+struct [[clang::suppress]] D1_Suppressed {
+  friend struct D1_FriendOuter;
+};
+struct D1_FriendOuter {
+  void method() {
+    // Defined outside the suppressed class — not suppressed.
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_D1() {
+  D1_FriendOuter{}.method();
+}
+
+// ============================================================================
+// Group E: Edge cases
+// ============================================================================
+
+// --- E1: friend function in suppressed CLASS TEMPLATE (not just suppressed 
class) ---
+
+template <typename U>
+struct [[clang::suppress]] E1_SuppressedTmpl {
+  friend void e1_friend(E1_SuppressedTmpl) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+void test_E1() {
+  e1_friend(E1_SuppressedTmpl<TypeA>{});
+}
+
+// --- E2: friend function template in a nested suppressed class ---
+// The friend needs a parameter of the nested class type for ADL lookup.
+
+struct Outer_E2 {
+  struct [[clang::suppress]] Inner_E2 {
+    template <typename T>
+    friend void e2_inner_friend(Inner_E2, T) {
+      clang_analyzer_warnIfReached(); // no-warning
+    }
+  };
+};
+void test_E2() {
+  e2_inner_friend(Outer_E2::Inner_E2{}, TypeA{});
+}
+
+// --- E3: multiple redeclarations at namespace scope before friend decl ---
+
+template <typename T> void e3_multi_redecl(T);
+template <typename T> void e3_multi_redecl(T);
+template <typename T> void e3_multi_redecl(T);
+struct [[clang::suppress]] E3_Suppressed {
+  template <typename T>
+  friend void e3_multi_redecl(T) {
+    // FIXME: This should be suppressed.
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_E3() {
+  e3_multi_redecl(TypeA{});
+}
+
+// --- E4: friend in anonymous namespace ---
+
+namespace {
+struct [[clang::suppress]] E4_AnonSuppressed {
+  friend void e4_anon_friend(E4_AnonSuppressed) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+} // namespace
+void test_E4() {
+  e4_anon_friend(E4_AnonSuppressed{});
+}
+
+// --- E5: suppression on the friend declaration itself, not on the class ---
+// Friend functions need a parameter for ADL visibility.
+
+struct E5_ClassNotSuppressed {
+  [[clang::suppress]] friend void e5_suppressed(E5_ClassNotSuppressed) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  friend void e5_unsuppressed(E5_ClassNotSuppressed) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_E5() {
+  e5_suppressed(E5_ClassNotSuppressed{});
+  e5_unsuppressed(E5_ClassNotSuppressed{});
+}
+
+// --- E6: friend function template in suppressed class template, with 
fwd-decl ---
+// Combines class template + function template + fwd-decl.
+
+template <typename T> void e6_combined(T);
+template <typename U>
+struct [[clang::suppress]] E6_SuppressedTmpl {
+  template <typename T>
+  friend void e6_combined(T) {
+    // FIXME: This should be suppressed.
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_E6() {
+  // Instantiate the class template to make the friend visible.
+  E6_SuppressedTmpl<TypeA> e6; // This line is IMPORTANT!
+  (void)e6;
+  e6_combined(TypeA{});
+}
+
+// --- E7: friend function template instantiated with multiple different types 
---
+// Ensure suppression applies to ALL instantiations, not just one.
+
+struct [[clang::suppress]] E7_Suppressed {
+  template <typename T>
+  friend void e7_multi_inst(E7_Suppressed, T) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+void test_E7() {
+  e7_multi_inst(E7_Suppressed{}, TypeA{});
+  e7_multi_inst(E7_Suppressed{}, TypeB{});
+}
+
+// --- E8: friend function template with fwd-decl, instantiated with multiple 
types ---
+
+template <typename T> void e8_fwd_multi(T);
+struct [[clang::suppress]] E8_Suppressed {
+  template <typename T>
+  friend void e8_fwd_multi(T) {
+    // FIXME: This should be suppressed.
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+void test_E8() {
+  e8_fwd_multi(TypeA{});
+  e8_fwd_multi(TypeB{});
+}
diff --git a/clang/test/Analysis/clang-suppress/function-templates.cpp 
b/clang/test/Analysis/clang-suppress/function-templates.cpp
new file mode 100644
index 0000000000000..dda7700fe7ae1
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/function-templates.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] on function templates and their
+// explicit specializations.
+
+// Placeholder types for triggering instantiations.
+// - Type should match an unconstrained template type parameter.
+// - Specialized should match a specialization pattern.
+struct Type{};
+struct Specialized{};
+
+// ============================================================================
+// Group A: Attribute on forward declaration only — NOT honored at definition
+// ============================================================================
+
+template <typename T> [[clang::suppress]] void FunctionTemplateSuppressed(T);
+template <typename T>
+void FunctionTemplateSuppressed(T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+template <typename T>
+void FunctionTemplateUnsuppressed(T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void test_fwd_decl_attr() {
+  FunctionTemplateSuppressed(Type{});
+  FunctionTemplateUnsuppressed(Type{});
+}
+
+// ============================================================================
+// Group B: Explicit full function specialization — attribute on specialization
+// ============================================================================
+
+// Only the Specialized specialization is suppressed.
+template <typename T>
+void ExplicitSpecAttrOnSpec(T) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+template <>
+[[clang::suppress]] void ExplicitSpecAttrOnSpec(Specialized) {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void test_attr_on_spec() {
+  ExplicitSpecAttrOnSpec(Type{});                // warns (primary)
+  ExplicitSpecAttrOnSpec(Specialized{});         // suppressed (explicit 
specialization)
+}
+
+// ============================================================================
+// Group C: Explicit full function specialization — attribute on primary
+// ============================================================================
+
+// Only the primary template is suppressed.
+template <typename T>
+[[clang::suppress]] void ExplicitSpecAttrOnPrimary(T) {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+template <>
+void ExplicitSpecAttrOnPrimary(Specialized) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void test_attr_on_primary() {
+  ExplicitSpecAttrOnPrimary(Type{});             // suppressed (primary)
+  ExplicitSpecAttrOnPrimary(Specialized{});      // warns (explicit 
specialization)
+}
+
+// ============================================================================
+// Group D: Variadic template with suppress + explicit specialization override
+// ============================================================================
+
+template <typename... Args>
+[[clang::suppress]] void Variadic_Suppressed(Args...) {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+// Variadic template function specialization — NOT suppressed.
+template <>
+void Variadic_Suppressed(Type, Specialized) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void test_variadic() {
+  Variadic_Suppressed();
+  Variadic_Suppressed(Type{});
+  Variadic_Suppressed(Type{}, Specialized{});
+}
diff --git a/clang/test/Analysis/clang-suppress/lambdas.cpp 
b/clang/test/Analysis/clang-suppress/lambdas.cpp
new file mode 100644
index 0000000000000..864069f957487
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/lambdas.cpp
@@ -0,0 +1,238 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] interaction with lambdas.
+
+// Placeholder type for triggering instantiations.
+struct Type{};
+
+// ============================================================================
+// Group A: Lambda in suppressed statement block
+// ============================================================================
+
+void lambda_in_suppressed_block() {
+  [[clang::suppress]] {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // no-warning
+    };
+    lam();
+  }
+}
+
+void lambda_in_unsuppressed_block() {
+  auto lam = []() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  };
+  lam();
+}
+
+// ============================================================================
+// Group B: Lambda in suppressed class method
+// ============================================================================
+
+struct [[clang::suppress]] B_SuppressedClass {
+  void method_with_lambda() {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // no-warning
+    };
+    lam();
+  }
+};
+
+struct B_UnsuppressedClass {
+  void method_with_lambda() {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    };
+    lam();
+  }
+};
+
+void test_B() {
+  B_SuppressedClass().method_with_lambda();
+  B_UnsuppressedClass().method_with_lambda();
+}
+
+// ============================================================================
+// Group C: Nested lambdas
+// ============================================================================
+
+void nested_lambda_suppressed() {
+  [[clang::suppress]] {
+    auto outer = []() {
+      auto inner = []() {
+        clang_analyzer_warnIfReached(); // no-warning
+      };
+      return inner();
+    };
+    return outer(); // no-warning
+  }
+}
+
+void nested_lambda_unsuppressed() {
+  auto outer = []() {
+    auto inner = []() {
+      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    };
+    inner();
+  };
+  outer();
+}
+
+// ============================================================================
+// Group D: Lambda with captures
+// ============================================================================
+
+int lambda_with_ref_capture_suppressed() {
+  int *x = 0;
+  [[clang::suppress]] {
+    auto lam = [&x]() {
+      return *x;
+    };
+    return lam(); // no-warning
+  }
+}
+
+int lambda_with_ref_capture_unsuppressed() {
+  int *x = 0;
+  auto lam = [&x]() {
+    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
+  };
+  return lam();
+}
+
+int lambda_capture_by_value_suppressed() {
+  int *x = 0;
+  [[clang::suppress]] {
+    auto lam = [x]() {
+      return *x;
+    };
+    return lam(); // no-warning
+  }
+}
+
+// ============================================================================
+// Group E: Lambda in suppressed namespace
+// ============================================================================
+
+namespace [[clang::suppress]] SuppressedNS {
+  void func_with_lambda() {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // no-warning
+    };
+    lam();
+  }
+} // namespace SuppressedNS
+
+// ============================================================================
+// Group F: Suppressed lambda, unsuppressed enclosing
+// ============================================================================
+
+void selective_suppression_unsup() {
+  auto unsuppressed_lam = []() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  };
+  unsuppressed_lam();
+}
+
+void selective_suppression_sup() {
+  [[clang::suppress]] auto suppressed_lam = []() {
+    clang_analyzer_warnIfReached(); // no-warning
+  };
+  suppressed_lam();
+}
+
+// ============================================================================
+// Group G: Lambda in template function
+// ============================================================================
+
+template <typename T>
+[[clang::suppress]] void tmpl_func_with_lambda(T) {
+  auto lam = []() {
+    clang_analyzer_warnIfReached(); // no-warning
+  };
+  lam();
+}
+
+template <typename T>
+void tmpl_func_with_lambda_unsuppressed(T) {
+  auto lam = []() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  };
+  lam();
+}
+
+void test_G() {
+  tmpl_func_with_lambda(Type{});
+  tmpl_func_with_lambda_unsuppressed(Type{});
+}
+
+// ============================================================================
+// Group H: Lambda in suppressed class template
+// ============================================================================
+
+template <typename T>
+struct [[clang::suppress]] H_SuppressedTmpl {
+  void method() {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // no-warning
+    };
+    lam();
+  }
+};
+
+template <typename T>
+struct H_UnsuppressedTmpl {
+  void method() {
+    auto lam = []() {
+      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    };
+    lam();
+  }
+};
+
+void test_H() {
+  H_SuppressedTmpl<Type>().method();
+  H_UnsuppressedTmpl<Type>().method();
+}
+
+// ============================================================================
+// Group I: Immediately-invoked lambda expression
+// ============================================================================
+
+int iile_suppressed() {
+  [[clang::suppress]] {
+    return []() {
+      int *x = 0;
+      return *x;
+    }(); // no-warning
+  }
+}
+
+int iile_unsuppressed() {
+  return []() {
+    int *x = 0;
+    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
+  }();
+}
+
+// ============================================================================
+// Group J: Generic lambda (C++14)
+// ============================================================================
+
+void generic_lambda_suppressed() {
+  [[clang::suppress]] {
+    auto lam = [](auto) {
+      clang_analyzer_warnIfReached(); // no-warning
+    };
+    lam(Type{});
+  }
+}
+
+void generic_lambda_unsuppressed() {
+  auto lam = [](auto) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  };
+  lam(Type{});
+}
diff --git a/clang/test/Analysis/clang-suppress/macros.cpp 
b/clang/test/Analysis/clang-suppress/macros.cpp
new file mode 100644
index 0000000000000..7458484a33b0a
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/macros.cpp
@@ -0,0 +1,186 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] interaction with macros.
+//
+// The fullyContains() function compares source ranges using
+// SourceManager::isBeforeInTranslationUnit, which handles macro
+// expansion locations. These tests verify that suppression works
+// correctly when bugs are reported inside macro expansions.
+
+// Placeholder type for triggering instantiations.
+struct Type{};
+
+// ============================================================================
+// Group A: Bug inside macro, suppression outside (using warnIfReached)
+// ============================================================================
+
+#define WARN clang_analyzer_warnIfReached()
+
+void macro_in_suppressed_block() {
+  [[clang::suppress]] {
+    WARN; // no-warning
+  }
+}
+
+void macro_in_unsuppressed_block() {
+  WARN; // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group B: Function-like macro with expression
+// ============================================================================
+
+#define DO_WARN() clang_analyzer_warnIfReached()
+
+void funclike_macro_suppressed() {
+  [[clang::suppress]] {
+    DO_WARN(); // no-warning
+  }
+}
+
+void funclike_macro_unsuppressed() {
+  DO_WARN(); // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group C: Nested macros
+// ============================================================================
+
+#define INNER_WARN() clang_analyzer_warnIfReached()
+#define OUTER_WARN() INNER_WARN()
+
+void nested_macro_suppressed() {
+  [[clang::suppress]] {
+    OUTER_WARN(); // no-warning
+  }
+}
+
+void nested_macro_unsuppressed() {
+  OUTER_WARN(); // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group D: Macro defining entire function body
+// ============================================================================
+
+#define BUGGY_BODY { clang_analyzer_warnIfReached(); }
+
+[[clang::suppress]] void func_with_macro_body()
+  BUGGY_BODY // no-warning
+
+void func_with_macro_body_unsuppressed()
+  BUGGY_BODY // expected-warning{{REACHABLE}}
+
+// ============================================================================
+// Group E: Macro in suppressed class method
+// ============================================================================
+
+struct [[clang::suppress]] MacroInSuppressedClass {
+  void method() {
+    WARN; // no-warning
+  }
+};
+
+struct MacroInUnsuppressedClass {
+  void method() {
+    WARN; // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_E() {
+  MacroInSuppressedClass().method();
+  MacroInUnsuppressedClass().method();
+}
+
+// ============================================================================
+// Group F: Macro expanding to suppression attribute + code
+// ============================================================================
+
+#define SUPPRESS_AND_WARN [[clang::suppress]] clang_analyzer_warnIfReached()
+
+void macro_suppression_wrapper() {
+  SUPPRESS_AND_WARN; // no-warning
+}
+
+// ============================================================================
+// Group G: Macro in template context
+// ============================================================================
+
+template <typename T>
+struct [[clang::suppress]] MacroInTemplate {
+  void method() {
+    WARN; // no-warning
+  }
+};
+
+template <typename T>
+struct MacroInTemplate_NoAttr {
+  void method() {
+    WARN; // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_G() {
+  MacroInTemplate<Type>().method();
+  MacroInTemplate_NoAttr<Type>().method();
+}
+
+// ============================================================================
+// Group H: Null dereference through direct null, suppressed at statement level
+// ============================================================================
+
+int macro_deref_suppressed() {
+  int *p = 0;
+  [[clang::suppress]] return *p; // no-warning
+}
+
+int macro_deref_unsuppressed() {
+  int *p = 0;
+  return *p; // expected-warning{{Dereference of null pointer (loaded from 
variable 'p')}}
+}
+
+// ============================================================================
+// Group I: Stringification and token pasting (shouldn't affect suppression)
+// ============================================================================
+
+#define STRINGIFY(x) #x
+#define CONCAT(a, b) a##b
+
+void stringify_suppressed() {
+  [[clang::suppress]] {
+    const char *s = STRINGIFY(hello);
+    (void)s;
+    int CONCAT(var, 1) = 0;
+    clang_analyzer_warnIfReached(); // no-warning
+    (void)var1;
+  }
+}
+
+void stringify_unsuppressed() {
+  const char *s = STRINGIFY(hello);
+  (void)s;
+  int CONCAT(var, 1) = 0;
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  (void)var1;
+}
+
+// ============================================================================
+// Group J: Multi-line macro with warnIfReached
+// ============================================================================
+
+#define MULTI_LINE_WARN  \
+  do {                   \
+    clang_analyzer_warnIfReached(); \
+  } while (0)
+
+void multiline_macro_suppressed() {
+  [[clang::suppress]] {
+    MULTI_LINE_WARN; // no-warning
+  }
+}
+
+void multiline_macro_unsuppressed() {
+  MULTI_LINE_WARN; // expected-warning{{REACHABLE}}
+}
diff --git a/clang/test/Analysis/clang-suppress/namespaces.cpp 
b/clang/test/Analysis/clang-suppress/namespaces.cpp
new file mode 100644
index 0000000000000..aa1d270ad405a
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/namespaces.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// Systematic tests for [[clang::suppress]] on namespaces.
+
+// ============================================================================
+// Group A: Attributed namespace suppresses inline definitions
+// ============================================================================
+
+namespace [[clang::suppress]]
+suppressed_namespace {
+  int foo() {
+    int *x = 0;
+    return *x; // no-warning: inside attributed namespace
+  }
+
+  int ool_foo();
+}
+
+// Out-of-line definition in an attributed namespace is NOT suppressed.
+int suppressed_namespace::ool_foo() {
+    int *x = 0;
+    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
+}
+
+// ============================================================================
+// Group B: Reopened namespace (without attribute) is NOT suppressed
+// ============================================================================
+
+// Another instance of the same namespace — the attribute does not carry over.
+namespace suppressed_namespace {
+  int bar() {
+    int *x = 0;
+    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
+  }
+}
diff --git a/clang/test/Analysis/clang-suppress/statements.cpp 
b/clang/test/Analysis/clang-suppress/statements.cpp
new file mode 100644
index 0000000000000..be3e1fd0f1832
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/statements.cpp
@@ -0,0 +1,158 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// ============================================================================
+// Group A: Compound statement (block)
+// ============================================================================
+
+void suppress_compound_suppressed() {
+  [[clang::suppress]] {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+}
+
+void suppress_compound_unsuppressed() {
+  {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group B: If statement
+// ============================================================================
+
+void suppress_if(bool coin) {
+  [[clang::suppress]] if (coin) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void suppress_if_else(bool coin) {
+  [[clang::suppress]] if (coin) {
+    clang_analyzer_warnIfReached(); // no-warning
+  } else {
+    clang_analyzer_warnIfReached(); // no-warning: entire if-else is suppressed
+  }
+}
+
+void unsuppressed_if_else(bool coin) {
+  if (coin) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  } else {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+// ============================================================================
+// Group C: Loop statements
+// ============================================================================
+
+void suppress_for(int n) {
+  [[clang::suppress]] for (int i = 0; i < n; ++i) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+}
+
+void suppress_while(int n) {
+  [[clang::suppress]] while (--n) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+}
+
+void suppress_do_while(int n) {
+  [[clang::suppress]] do {
+    clang_analyzer_warnIfReached(); // no-warning
+  } while (--n);
+}
+
+void unsuppressed_for(int n) {
+  for (int i = 0; i < n; ++i) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+}
+
+void suppress_range_for() {
+  int arr[] = {1, 2, 3};
+  [[clang::suppress]] for (int x : arr) {
+    clang_analyzer_warnIfReached(); // no-warning
+    (void)x;
+  }
+}
+
+// ============================================================================
+// Group D: Switch statement
+// ============================================================================
+
+int suppress_switch(int n) {
+  [[clang::suppress]] switch (n) {
+  case 1:
+    return clang_analyzer_warnIfReached(), 1; // no-warning
+  default:
+    break;
+  }
+  return 0;
+}
+
+int unsuppressed_switch(int n) {
+  switch (n) {
+  case 1:
+    return clang_analyzer_warnIfReached(), 1; // expected-warning{{REACHABLE}}
+  default:
+    break;
+  }
+  return 0;
+}
+
+// ============================================================================
+// Group E: Return statement
+// ============================================================================
+
+int suppress_return() {
+  [[clang::suppress]] return clang_analyzer_warnIfReached(), 1; // no-warning
+}
+
+int unsuppressed_return() {
+  return clang_analyzer_warnIfReached(), 1; // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group F: Expression statement
+// ============================================================================
+
+void suppress_expr_stmt() {
+  [[clang::suppress]] clang_analyzer_warnIfReached(); // no-warning
+}
+
+void unsuppressed_expr_stmt() {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+// ============================================================================
+// Group G: Nested suppressed blocks
+// ============================================================================
+
+void nested_suppression() {
+  [[clang::suppress]] {
+    [[clang::suppress]] {
+      clang_analyzer_warnIfReached(); // no-warning
+    }
+  }
+}
+
+// ============================================================================
+// Group H: Suppression on single statement within method
+// ============================================================================
+
+struct H_ClassWithMethods {
+  void method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    [[clang::suppress]] clang_analyzer_warnIfReached(); // no-warning
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_H() {
+  H_ClassWithMethods().method();
+}
diff --git a/clang/test/Analysis/clang-suppress/template-methods.cpp 
b/clang/test/Analysis/clang-suppress/template-methods.cpp
new file mode 100644
index 0000000000000..fb692aa7f0d46
--- /dev/null
+++ b/clang/test/Analysis/clang-suppress/template-methods.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_warnIfReached();
+
+// Systematic tests for [[clang::suppress]] on template methods inside
+// non-template and template classes.
+
+// Placeholder types for triggering instantiations.
+// - Type{A,B} should match an unconstrained template type parameter.
+struct TypeA{};
+struct TypeB{};
+
+// ============================================================================
+// Group A: Non-template class with suppressed/unsuppressed template methods
+// ============================================================================
+
+struct NonTemplateClassWithTemplatedMethod {
+  template <typename T>
+  [[clang::suppress]] void suppressed(T) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+
+  template <typename T>
+  void unsuppressed(T) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_nontpl_class() {
+  NonTemplateClassWithTemplatedMethod().suppressed(TypeA{});
+  NonTemplateClassWithTemplatedMethod().unsuppressed(TypeA{});
+}
+
+// ============================================================================
+// Group B: Template class with template methods — inline
+// ============================================================================
+
+template <typename T>
+struct TemplateClassWithTemplateMethod {
+  template <typename U>
+  [[clang::suppress]] void suppressed(U) {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+
+  template <typename U>
+  void unsuppressed(U) {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+
+  template <typename U>
+  [[clang::suppress]] void suppress_at_decl_outline(U);
+
+  template <typename U>
+  void suppress_at_def_outline(U);
+};
+
+// ============================================================================
+// Group C: Template class with template methods — out-of-line
+// ============================================================================
+
+// Attribute on declaration only — NOT honored at out-of-line definition.
+template <typename T>
+template <typename U>
+void TemplateClassWithTemplateMethod<T>::suppress_at_decl_outline(U) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+// Attribute on out-of-line definition — suppressed.
+template <typename T>
+template <typename U>
+[[clang::suppress]] void 
TemplateClassWithTemplateMethod<T>::suppress_at_def_outline(U) {
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void test_tpl_class_tpl_method() {
+  TemplateClassWithTemplateMethod<TypeA>().suppressed(TypeB{});
+  TemplateClassWithTemplateMethod<TypeA>().unsuppressed(TypeB{});
+  TemplateClassWithTemplateMethod<TypeA>().suppress_at_decl_outline(TypeB{});
+  TemplateClassWithTemplateMethod<TypeA>().suppress_at_def_outline(TypeB{});
+}
+
+// ============================================================================
+// Group D: Template-template parameters
+// ============================================================================
+
+// A simple "box" template used as a template-template argument.
+template <typename T>
+struct Box {
+  void get() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+// A version of Box that suppresses its own methods.
+template <typename T>
+class [[clang::suppress]] SuppressedBox {
+public:
+  void get() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+// Adaptor whose own methods are suppressed; the contained Box's methods are 
not.
+template <typename T, template <typename> class Container>
+class [[clang::suppress]] SuppressedAdaptor {
+public:
+  Container<T> data;
+
+  void adaptor_method() {
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};
+
+// Adaptor with no suppression; Box's own suppression is independent.
+template <typename T, template <typename> class Container>
+struct UnsuppressedAdaptor {
+  Container<T> data;
+
+  void adaptor_method() {
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  }
+};
+
+void test_template_template() {
+  // SuppressedAdaptor<Box>: adaptor method suppressed; Box::get not affected.
+  SuppressedAdaptor<TypeA, Box>().adaptor_method();  // suppressed by 
adaptor's attr
+  SuppressedAdaptor<TypeA, Box>().data.get();        // warns — Box has no 
attr, different lexical context
+
+  // UnsuppressedAdaptor<SuppressedBox>: adaptor warns; SuppressedBox::get 
suppressed.
+  UnsuppressedAdaptor<TypeA, SuppressedBox>().adaptor_method();  // warns — 
adaptor has no attr
+  UnsuppressedAdaptor<TypeA, SuppressedBox>().data.get();        // suppressed 
by SuppressedBox's attr
+}
diff --git a/clang/test/Analysis/suppression-attr.cpp 
b/clang/test/Analysis/suppression-attr.cpp
deleted file mode 100644
index 9ba56d976fddb..0000000000000
--- a/clang/test/Analysis/suppression-attr.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
-
-void clang_analyzer_warnIfReached();
-
-struct Clazz {
-  template <typename T>
-  static void templated_memfn();
-};
-
-// This must come before the 'templated_memfn' is defined!
-static void instantiate() {
-  Clazz::templated_memfn<int>();
-}
-
-template <typename T>
-void Clazz::templated_memfn() {
-  // When we report a bug in a function, we traverse the lexical decl context
-  // of it while looking for suppression attributes to record what source
-  // ranges should the suppression apply to.
-  // In the past, that traversal didn't follow template instantiations, only
-  // primary templates.
-  [[clang::suppress]] clang_analyzer_warnIfReached(); // no-warning
-
-}
-
-namespace [[clang::suppress]]
-suppressed_namespace {
-  int foo() {
-    int *x = 0;
-    return *x;
-  }
-
-  int foo_forward();
-}
-
-int suppressed_namespace::foo_forward() {
-    int *x = 0;
-    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
-}
-
-// Another instance of the same namespace.
-namespace suppressed_namespace {
-  int bar() {
-    int *x = 0;
-    return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
-  }
-}
-
-void lambda() {
-  [[clang::suppress]] {
-    auto lam = []() {
-      int *x = 0;
-      return *x;
-    };
-  }
-}
-
-class [[clang::suppress]] SuppressedClass {
-  int foo() {
-    int *x = 0;
-    return *x;
-  }
-
-  int bar();
-};
-
-int SuppressedClass::bar() {
-  int *x = 0;
-  return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
-}
-
-class SuppressedMethodClass {
-  [[clang::suppress]] int foo() {
-    int *x = 0;
-    return *x;
-  }
-
-  [[clang::suppress]] int bar1();
-  int bar2();
-};
-
-int SuppressedMethodClass::bar1() {
-  int *x = 0;
-  return *x; // expected-warning{{Dereference of null pointer (loaded from 
variable 'x')}}
-}
-
-[[clang::suppress]]
-int SuppressedMethodClass::bar2() {
-  int *x = 0;
-  return *x; // no-warning
-}

From b932d955ffe21adf8a777d41e8f633ab34364d9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20Benics?= <[email protected]>
Date: Mon, 16 Mar 2026 15:16:18 +0000
Subject: [PATCH 2/3] namespace -> TU in comments
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Donát Nagy <[email protected]>
Co-authored-by: Balázs Benics <[email protected]>
---
 .../Analysis/clang-suppress/class-template-specializations.cpp  | 2 +-
 clang/test/Analysis/clang-suppress/friends.cpp                  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git 
a/clang/test/Analysis/clang-suppress/class-template-specializations.cpp 
b/clang/test/Analysis/clang-suppress/class-template-specializations.cpp
index 1d1202ca70ff7..94f18a41164d6 100644
--- a/clang/test/Analysis/clang-suppress/class-template-specializations.cpp
+++ b/clang/test/Analysis/clang-suppress/class-template-specializations.cpp
@@ -29,7 +29,7 @@ class [[clang::suppress]] A_Primary {
 
 template <typename T>
 void A_Primary<T>::outline_method() {
-  // Out-of-line: lexical context is namespace.
+  // Out-of-line: lexical context is the translation unit.
   clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 }
 
diff --git a/clang/test/Analysis/clang-suppress/friends.cpp 
b/clang/test/Analysis/clang-suppress/friends.cpp
index 430699aa2d8b2..acd3193eca0e2 100644
--- a/clang/test/Analysis/clang-suppress/friends.cpp
+++ b/clang/test/Analysis/clang-suppress/friends.cpp
@@ -46,7 +46,7 @@ struct [[clang::suppress]] A2_Suppressed {
   friend void a2_suppressed(A2_Suppressed);
 };
 void a2_suppressed(A2_Suppressed) {
-  // Out-of-line: lexical parent is the namespace, NOT the class.
+  // Out-of-line: lexical parent is the translation unit, NOT the class.
   clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 }
 struct A2_Unsuppressed {

From c6161179298864344885b348c194a3d1b7a391a3 Mon Sep 17 00:00:00 2001
From: Balazs Benics <[email protected]>
Date: Mon, 16 Mar 2026 15:21:56 +0000
Subject: [PATCH 3/3] Split the template-methods.cpp Group B and C group
 commonalities

---
 .../clang-suppress/template-methods.cpp       | 28 +++++++++++--------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/clang/test/Analysis/clang-suppress/template-methods.cpp 
b/clang/test/Analysis/clang-suppress/template-methods.cpp
index fb692aa7f0d46..7d18d7d68bc6e 100644
--- a/clang/test/Analysis/clang-suppress/template-methods.cpp
+++ b/clang/test/Analysis/clang-suppress/template-methods.cpp
@@ -46,7 +46,19 @@ struct TemplateClassWithTemplateMethod {
   void unsuppressed(U) {
     clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
   }
+};
+
+void test_tpl_class_tpl_inline_method() {
+  TemplateClassWithTemplateMethod<TypeA>().suppressed(TypeB{});
+  TemplateClassWithTemplateMethod<TypeA>().unsuppressed(TypeB{});
+}
+
+// ============================================================================
+// Group C: Template class with template methods — out-of-line
+// ============================================================================
 
+template <typename T>
+struct TemplateClassWithTemplateOOLMethod {
   template <typename U>
   [[clang::suppress]] void suppress_at_decl_outline(U);
 
@@ -54,29 +66,23 @@ struct TemplateClassWithTemplateMethod {
   void suppress_at_def_outline(U);
 };
 
-// ============================================================================
-// Group C: Template class with template methods — out-of-line
-// ============================================================================
-
 // Attribute on declaration only — NOT honored at out-of-line definition.
 template <typename T>
 template <typename U>
-void TemplateClassWithTemplateMethod<T>::suppress_at_decl_outline(U) {
+void TemplateClassWithTemplateOOLMethod<T>::suppress_at_decl_outline(U) {
   clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 }
 
 // Attribute on out-of-line definition — suppressed.
 template <typename T>
 template <typename U>
-[[clang::suppress]] void 
TemplateClassWithTemplateMethod<T>::suppress_at_def_outline(U) {
+[[clang::suppress]] void 
TemplateClassWithTemplateOOLMethod<T>::suppress_at_def_outline(U) {
   clang_analyzer_warnIfReached(); // no-warning
 }
 
-void test_tpl_class_tpl_method() {
-  TemplateClassWithTemplateMethod<TypeA>().suppressed(TypeB{});
-  TemplateClassWithTemplateMethod<TypeA>().unsuppressed(TypeB{});
-  TemplateClassWithTemplateMethod<TypeA>().suppress_at_decl_outline(TypeB{});
-  TemplateClassWithTemplateMethod<TypeA>().suppress_at_def_outline(TypeB{});
+void test_tpl_class_tpl_ool_method() {
+  
TemplateClassWithTemplateOOLMethod<TypeA>().suppress_at_decl_outline(TypeB{});
+  TemplateClassWithTemplateOOLMethod<TypeA>().suppress_at_def_outline(TypeB{});
 }
 
 // ============================================================================

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

Reply via email to