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

From d4878a62a69304dc2ae32902803f8c8efb1c69ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com>
Date: Thu, 20 Mar 2025 17:09:46 +0100
Subject: [PATCH 1/4] [NFC][analyzer] Multipart checker refactor 2:
 NullabilityChecker

Simplify `NullabilityChecker.cpp` with new multipart checker framework
introduced in 27099982da2f5a6c2d282d6b385e79d080669546. This is part of
a commit series that will perform analogous changes in all checker
classes that implement multiple user-facing checker parts (with separate
names).
---
 .../Checkers/NullabilityChecker.cpp           | 157 +++++++++---------
 1 file changed, 81 insertions(+), 76 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 04472bb3895a7..8fe7d21ca7984 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -112,25 +112,38 @@ class NullabilityChecker
   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
                   const char *Sep) const override;
 
-  enum CheckKind {
-    CK_NullPassedToNonnull,
-    CK_NullReturnedFromNonnull,
-    CK_NullableDereferenced,
-    CK_NullablePassedToNonnull,
-    CK_NullableReturnedFromNonnull,
-    CK_NumCheckKinds
+  // FIXME: This enumeration of checker parts is extremely similar to the
+  // ErrorKind enum. It would be nice to unify them to simplify the code.
+  // FIXME: The modeling checker NullabilityBase is a dummy "empty checker
+  // part" that registers this checker class without enabling any of the real
+  // checker parts. As far as I understand no other checker references it, so
+  // it should be removed.
+  enum : CheckerPartIdx {
+    NullabilityBase,
+    NullPassedToNonnullChecker,
+    NullReturnedFromNonnullChecker,
+    NullableDereferencedChecker,
+    NullablePassedToNonnullChecker,
+    NullableReturnedFromNonnullChecker,
+    NumCheckerParts
   };
 
-  bool ChecksEnabled[CK_NumCheckKinds] = {false};
-  CheckerNameRef CheckNames[CK_NumCheckKinds];
-  mutable std::unique_ptr<BugType> BTs[CK_NumCheckKinds];
-
-  const std::unique_ptr<BugType> &getBugType(CheckKind Kind) const {
-    if (!BTs[Kind])
-      BTs[Kind].reset(new BugType(CheckNames[Kind], "Nullability",
-                                  categories::MemoryError));
-    return BTs[Kind];
-  }
+  // FIXME: Currently the `Description` fields of these `BugType`s are all
+  // identical ("Nullability") -- they should be more descriptive than this.
+  // NOTE: NullabilityBase is a dummy checker part that does nothing, so its
+  // bug type is left empty.
+  BugType BugTypes[NumCheckerParts] = {
+      {this, NullabilityBase, "", ""},
+      {this, NullPassedToNonnullChecker, "Nullability",
+       categories::MemoryError},
+      {this, NullReturnedFromNonnullChecker, "Nullability",
+       categories::MemoryError},
+      {this, NullableDereferencedChecker, "Nullability",
+       categories::MemoryError},
+      {this, NullablePassedToNonnullChecker, "Nullability",
+       categories::MemoryError},
+      {this, NullableReturnedFromNonnullChecker, "Nullability",
+       categories::MemoryError}};
 
   // When set to false no nullability information will be tracked in
   // NullabilityMap. It is possible to catch errors like passing a null pointer
@@ -163,17 +176,16 @@ class NullabilityChecker
   ///
   /// When \p SuppressPath is set to true, no more bugs will be reported on 
this
   /// path by this checker.
-  void reportBugIfInvariantHolds(StringRef Msg, ErrorKind Error, CheckKind CK,
-                                 ExplodedNode *N, const MemRegion *Region,
-                                 CheckerContext &C,
+  void reportBugIfInvariantHolds(StringRef Msg, ErrorKind Error,
+                                 CheckerPartIdx Idx, ExplodedNode *N,
+                                 const MemRegion *Region, CheckerContext &C,
                                  const Stmt *ValueExpr = nullptr,
                                  bool SuppressPath = false) const;
 
-  void reportBug(StringRef Msg, ErrorKind Error, CheckKind CK, ExplodedNode *N,
-                 const MemRegion *Region, BugReporter &BR,
+  void reportBug(StringRef Msg, ErrorKind Error, CheckerPartIdx Idx,
+                 ExplodedNode *N, const MemRegion *Region, BugReporter &BR,
                  const Stmt *ValueExpr = nullptr) const {
-    const std::unique_ptr<BugType> &BT = getBugType(CK);
-    auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
+    auto R = std::make_unique<PathSensitiveBugReport>(BugTypes[Idx], Msg, N);
     if (Region) {
       R->markInteresting(Region);
       R->addVisitor<NullabilityBugVisitor>(Region);
@@ -479,7 +491,7 @@ static bool checkInvariantViolation(ProgramStateRef State, 
ExplodedNode *N,
 }
 
 void NullabilityChecker::reportBugIfInvariantHolds(
-    StringRef Msg, ErrorKind Error, CheckKind CK, ExplodedNode *N,
+    StringRef Msg, ErrorKind Error, CheckerPartIdx Idx, ExplodedNode *N,
     const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr,
     bool SuppressPath) const {
   ProgramStateRef OriginalState = N->getState();
@@ -491,7 +503,7 @@ void NullabilityChecker::reportBugIfInvariantHolds(
     N = C.addTransition(OriginalState, N);
   }
 
-  reportBug(Msg, Error, CK, N, Region, C.getBugReporter(), ValueExpr);
+  reportBug(Msg, Error, Idx, N, Region, C.getBugReporter(), ValueExpr);
 }
 
 /// Cleaning up the program state.
@@ -545,19 +557,19 @@ void 
NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {
   if (!TrackedNullability)
     return;
 
-  if (ChecksEnabled[CK_NullableDereferenced] &&
+  if (isPartEnabled(NullableDereferencedChecker) &&
       TrackedNullability->getValue() == Nullability::Nullable) {
     BugReporter &BR = *Event.BR;
     // Do not suppress errors on defensive code paths, because dereferencing
     // a nullable pointer is always an error.
     if (Event.IsDirectDereference)
       reportBug("Nullable pointer is dereferenced",
-                ErrorKind::NullableDereferenced, CK_NullableDereferenced,
+                ErrorKind::NullableDereferenced, NullableDereferencedChecker,
                 Event.SinkNode, Region, BR);
     else {
       reportBug("Nullable pointer is passed to a callee that requires a "
                 "non-null",
-                ErrorKind::NullablePassedToNonnull, CK_NullableDereferenced,
+                ErrorKind::NullablePassedToNonnull, 
NullableDereferencedChecker,
                 Event.SinkNode, Region, BR);
     }
   }
@@ -711,7 +723,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
 
   bool NullReturnedFromNonNull = (RequiredNullability == Nullability::Nonnull 
&&
                                   Nullness == NullConstraint::IsNull);
-  if (ChecksEnabled[CK_NullReturnedFromNonnull] && NullReturnedFromNonNull &&
+  if (isPartEnabled(NullReturnedFromNonnullChecker) &&
+      NullReturnedFromNonNull &&
       RetExprTypeLevelNullability != Nullability::Nonnull &&
       !InSuppressedMethodFamily) {
     static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
@@ -725,7 +738,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
     OS << " returned from a " << C.getDeclDescription(D) <<
           " that is expected to return a non-null value";
     reportBugIfInvariantHolds(OS.str(), ErrorKind::NilReturnedToNonnull,
-                              CK_NullReturnedFromNonnull, N, nullptr, C,
+                              NullReturnedFromNonnullChecker, N, nullptr, C,
                               RetExpr);
     return;
   }
@@ -746,7 +759,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
       State->get<NullabilityMap>(Region);
   if (TrackedNullability) {
     Nullability TrackedNullabValue = TrackedNullability->getValue();
-    if (ChecksEnabled[CK_NullableReturnedFromNonnull] &&
+    if (isPartEnabled(NullableReturnedFromNonnullChecker) &&
         Nullness != NullConstraint::IsNotNull &&
         TrackedNullabValue == Nullability::Nullable &&
         RequiredNullability == Nullability::Nonnull) {
@@ -759,7 +772,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
             " that is expected to return a non-null value";
 
       reportBugIfInvariantHolds(OS.str(), ErrorKind::NullableReturnedToNonnull,
-                                CK_NullableReturnedFromNonnull, N, Region, C);
+                                NullableReturnedFromNonnullChecker, N, Region,
+                                C);
     }
     return;
   }
@@ -810,7 +824,7 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
 
     unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
 
-    if (ChecksEnabled[CK_NullPassedToNonnull] &&
+    if (isPartEnabled(NullPassedToNonnullChecker) &&
         Nullness == NullConstraint::IsNull &&
         ArgExprTypeLevelNullability != Nullability::Nonnull &&
         RequiredNullability == Nullability::Nonnull &&
@@ -825,7 +839,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
       OS << " passed to a callee that requires a non-null " << ParamIdx
          << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
       reportBugIfInvariantHolds(OS.str(), ErrorKind::NilPassedToNonnull,
-                                CK_NullPassedToNonnull, N, nullptr, C, ArgExpr,
+                                NullPassedToNonnullChecker, N, nullptr, C,
+                                ArgExpr,
                                 /*SuppressPath=*/false);
       return;
     }
@@ -842,7 +857,7 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
           TrackedNullability->getValue() != Nullability::Nullable)
         continue;
 
-      if (ChecksEnabled[CK_NullablePassedToNonnull] &&
+      if (isPartEnabled(NullablePassedToNonnullChecker) &&
           RequiredNullability == Nullability::Nonnull &&
           isDiagnosableCall(Call)) {
         ExplodedNode *N = C.addTransition(State);
@@ -851,16 +866,16 @@ void NullabilityChecker::checkPreCall(const CallEvent 
&Call,
         OS << "Nullable pointer is passed to a callee that requires a non-null 
"
            << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
         reportBugIfInvariantHolds(OS.str(), ErrorKind::NullablePassedToNonnull,
-                                  CK_NullablePassedToNonnull, N, Region, C,
+                                  NullablePassedToNonnullChecker, N, Region, C,
                                   ArgExpr, /*SuppressPath=*/true);
         return;
       }
-      if (ChecksEnabled[CK_NullableDereferenced] &&
+      if (isPartEnabled(NullableDereferencedChecker) &&
           Param->getType()->isReferenceType()) {
         ExplodedNode *N = C.addTransition(State);
         reportBugIfInvariantHolds("Nullable pointer is dereferenced",
                                   ErrorKind::NullableDereferenced,
-                                  CK_NullableDereferenced, N, Region, C,
+                                  NullableDereferencedChecker, N, Region, C,
                                   ArgExpr, /*SuppressPath=*/true);
         return;
       }
@@ -1295,7 +1310,7 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const 
Stmt *S,
 
   bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&
                                 RhsNullness == NullConstraint::IsNull);
-  if (ChecksEnabled[CK_NullPassedToNonnull] && NullAssignedToNonNull &&
+  if (isPartEnabled(NullPassedToNonnullChecker) && NullAssignedToNonNull &&
       ValNullability != Nullability::Nonnull &&
       ValueExprTypeLevelNullability != Nullability::Nonnull &&
       !isARCNilInitializedLocal(C, S)) {
@@ -1314,7 +1329,8 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const 
Stmt *S,
     OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null");
     OS << " assigned to a pointer which is expected to have non-null value";
     reportBugIfInvariantHolds(OS.str(), ErrorKind::NilAssignedToNonnull,
-                              CK_NullPassedToNonnull, N, nullptr, C, 
ValueStmt);
+                              NullPassedToNonnullChecker, N, nullptr, C,
+                              ValueStmt);
     return;
   }
 
@@ -1340,14 +1356,15 @@ void NullabilityChecker::checkBind(SVal L, SVal V, 
const Stmt *S,
     if (RhsNullness == NullConstraint::IsNotNull ||
         TrackedNullability->getValue() != Nullability::Nullable)
       return;
-    if (ChecksEnabled[CK_NullablePassedToNonnull] &&
+    if (isPartEnabled(NullablePassedToNonnullChecker) &&
         LocNullability == Nullability::Nonnull) {
       static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
       ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
       reportBugIfInvariantHolds("Nullable pointer is assigned to a pointer "
                                 "which is expected to have non-null value",
                                 ErrorKind::NullableAssignedToNonnull,
-                                CK_NullablePassedToNonnull, N, ValueRegion, C);
+                                NullablePassedToNonnullChecker, N, ValueRegion,
+                                C);
     }
     return;
   }
@@ -1394,38 +1411,26 @@ void NullabilityChecker::printState(raw_ostream &Out, 
ProgramStateRef State,
   }
 }
 
-void ento::registerNullabilityBase(CheckerManager &mgr) {
-  mgr.registerChecker<NullabilityChecker>();
-}
-
-bool ento::shouldRegisterNullabilityBase(const CheckerManager &mgr) {
-  return true;
-}
-
-#define REGISTER_CHECKER(name, trackingRequired)                               
\
-  void ento::register##name##Checker(CheckerManager &mgr) {                    
\
-    NullabilityChecker *checker = mgr.getChecker<NullabilityChecker>();        
\
-    checker->ChecksEnabled[NullabilityChecker::CK_##name] = true;              
\
-    checker->CheckNames[NullabilityChecker::CK_##name] =                       
\
-        mgr.getCurrentCheckerName();                                           
\
-    checker->NeedTracking = checker->NeedTracking || trackingRequired;         
\
-    checker->NoDiagnoseCallsToSystemHeaders =                                  
\
-        checker->NoDiagnoseCallsToSystemHeaders ||                             
\
-        mgr.getAnalyzerOptions().getCheckerBooleanOption(                      
\
-            checker, "NoDiagnoseCallsToSystemHeaders", true);                  
\
+#define REGISTER_CHECKER(Part, TrackingRequired)                               
\
+  void ento::register##Part(CheckerManager &Mgr) {                             
\
+    auto *Checker =                                                            
\
+        Mgr.registerChecker<NullabilityChecker, NullabilityChecker::Part>();   
\
+    Checker->NeedTracking = Checker->NeedTracking || TrackingRequired;         
\
+    Checker->NoDiagnoseCallsToSystemHeaders =                                  
\
+        Checker->NoDiagnoseCallsToSystemHeaders ||                             
\
+        Mgr.getAnalyzerOptions().getCheckerBooleanOption(                      
\
+            Checker, "NoDiagnoseCallsToSystemHeaders", true);                  
\
   }                                                                            
\
                                                                                
\
-  bool ento::shouldRegister##name##Checker(const CheckerManager &mgr) {        
\
-    return true;                                                               
\
-  }
-
-// The checks are likely to be turned on by default and it is possible to do
-// them without tracking any nullability related information. As an 
optimization
-// no nullability information will be tracked when only these two checks are
-// enables.
-REGISTER_CHECKER(NullPassedToNonnull, false)
-REGISTER_CHECKER(NullReturnedFromNonnull, false)
-
-REGISTER_CHECKER(NullableDereferenced, true)
-REGISTER_CHECKER(NullablePassedToNonnull, true)
-REGISTER_CHECKER(NullableReturnedFromNonnull, true)
+  bool ento::shouldRegister##Part(const CheckerManager &) { return true; }
+
+// These checker parts are likely to be turned on by default and they don't
+// need the tracking of nullability related information. As an optimization
+// nullability information won't be tracked when the rest are disabled.
+REGISTER_CHECKER(NullabilityBase, false)
+REGISTER_CHECKER(NullPassedToNonnullChecker, false)
+REGISTER_CHECKER(NullReturnedFromNonnullChecker, false)
+
+REGISTER_CHECKER(NullableDereferencedChecker, true)
+REGISTER_CHECKER(NullablePassedToNonnullChecker, true)
+REGISTER_CHECKER(NullableReturnedFromNonnullChecker, true)

From 2708bed01435d5953bf0446626f7c1e6727fef31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com>
Date: Thu, 20 Mar 2025 17:52:24 +0100
Subject: [PATCH 2/4] Remove hidden dummy checker part NullabilityBase

As far as I see it was just a hacky implementation detail within the
old solution for registering the "real" checker parts. I'm placing this
into a separate commit to make the review easier.
---
 .../clang/StaticAnalyzer/Checkers/Checkers.td | 56 +++++++++----------
 .../Checkers/NullabilityChecker.cpp           | 32 +++++------
 .../test/Analysis/analyzer-enabled-checkers.c |  1 -
 clang/test/Analysis/bugfix-124477.m           |  2 +-
 ...c-library-functions-arg-enabled-checkers.c |  1 -
 5 files changed, 41 insertions(+), 51 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 35df4e7003ac9..0df5304ccf939 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -326,39 +326,37 @@ def StdVariantChecker : Checker<"StdVariant">,
 
 let ParentPackage = Nullability in {
 
-def NullabilityBase : Checker<"NullabilityBase">,
-  HelpText<"Stores information during the analysis about nullability.">,
-  Documentation<NotDocumented>,
-  Hidden;
-
-def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
-  HelpText<"Warns when a null pointer is passed to a pointer which has a "
-           "_Nonnull type.">,
-  Dependencies<[NullabilityBase]>,
-  Documentation<HasDocumentation>;
+  def NullPassedToNonnullChecker
+      : Checker<"NullPassedToNonnull">,
+        HelpText<"Warns when a null pointer is passed to a pointer which has a 
"
+                 "_Nonnull type.">,
+        Documentation<HasDocumentation>;
 
-def NullReturnedFromNonnullChecker : Checker<"NullReturnedFromNonnull">,
-  HelpText<"Warns when a null pointer is returned from a function that has "
-           "_Nonnull return type.">,
-  Dependencies<[NullabilityBase]>,
-  Documentation<HasDocumentation>;
+  def NullReturnedFromNonnullChecker
+      : Checker<"NullReturnedFromNonnull">,
+        HelpText<
+            "Warns when a null pointer is returned from a function that has "
+            "_Nonnull return type.">,
+        Documentation<HasDocumentation>;
 
-def NullableDereferencedChecker : Checker<"NullableDereferenced">,
-  HelpText<"Warns when a nullable pointer is dereferenced.">,
-  Dependencies<[NullabilityBase]>,
-  Documentation<HasDocumentation>;
+  def NullableDereferencedChecker
+      : Checker<"NullableDereferenced">,
+        HelpText<"Warns when a nullable pointer is dereferenced.">,
+        Documentation<HasDocumentation>;
 
-def NullablePassedToNonnullChecker : Checker<"NullablePassedToNonnull">,
-  HelpText<"Warns when a nullable pointer is passed to a pointer which has a "
-           "_Nonnull type.">,
-  Dependencies<[NullabilityBase]>,
-  Documentation<HasDocumentation>;
+  def NullablePassedToNonnullChecker
+      : Checker<"NullablePassedToNonnull">,
+        HelpText<
+            "Warns when a nullable pointer is passed to a pointer which has a "
+            "_Nonnull type.">,
+        Documentation<HasDocumentation>;
 
-def NullableReturnedFromNonnullChecker : 
Checker<"NullableReturnedFromNonnull">,
-  HelpText<"Warns when a nullable pointer is returned from a function that has 
"
-           "_Nonnull return type.">,
-  Dependencies<[NullabilityBase]>,
-  Documentation<NotDocumented>;
+  def NullableReturnedFromNonnullChecker
+      : Checker<"NullableReturnedFromNonnull">,
+        HelpText<"Warns when a nullable pointer is returned from a function "
+                 "that has "
+                 "_Nonnull return type.">,
+        Documentation<NotDocumented>;
 
 } // end "nullability"
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 8fe7d21ca7984..0129f6132e208 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -114,12 +114,7 @@ class NullabilityChecker
 
   // FIXME: This enumeration of checker parts is extremely similar to the
   // ErrorKind enum. It would be nice to unify them to simplify the code.
-  // FIXME: The modeling checker NullabilityBase is a dummy "empty checker
-  // part" that registers this checker class without enabling any of the real
-  // checker parts. As far as I understand no other checker references it, so
-  // it should be removed.
   enum : CheckerPartIdx {
-    NullabilityBase,
     NullPassedToNonnullChecker,
     NullReturnedFromNonnullChecker,
     NullableDereferencedChecker,
@@ -130,10 +125,7 @@ class NullabilityChecker
 
   // FIXME: Currently the `Description` fields of these `BugType`s are all
   // identical ("Nullability") -- they should be more descriptive than this.
-  // NOTE: NullabilityBase is a dummy checker part that does nothing, so its
-  // bug type is left empty.
   BugType BugTypes[NumCheckerParts] = {
-      {this, NullabilityBase, "", ""},
       {this, NullPassedToNonnullChecker, "Nullability",
        categories::MemoryError},
       {this, NullReturnedFromNonnullChecker, "Nullability",
@@ -1412,25 +1404,27 @@ void NullabilityChecker::printState(raw_ostream &Out, 
ProgramStateRef State,
 }
 
 #define REGISTER_CHECKER(Part, TrackingRequired)                               
\
-  void ento::register##Part(CheckerManager &Mgr) {                             
\
-    auto *Checker =                                                            
\
-        Mgr.registerChecker<NullabilityChecker, NullabilityChecker::Part>();   
\
+  void ento::register##Part##Checker(CheckerManager &Mgr) {                    
\
+    auto *Checker = Mgr.registerChecker<NullabilityChecker,                    
\
+                                        NullabilityChecker::Part##Checker>();  
\
     Checker->NeedTracking = Checker->NeedTracking || TrackingRequired;         
\
     Checker->NoDiagnoseCallsToSystemHeaders =                                  
\
         Checker->NoDiagnoseCallsToSystemHeaders ||                             
\
         Mgr.getAnalyzerOptions().getCheckerBooleanOption(                      
\
-            Checker, "NoDiagnoseCallsToSystemHeaders", true);                  
\
+            Mgr.getCurrentCheckerName(), "NoDiagnoseCallsToSystemHeaders",     
\
+            true);                                                             
\
   }                                                                            
\
                                                                                
\
-  bool ento::shouldRegister##Part(const CheckerManager &) { return true; }
+  bool ento::shouldRegister##Part##Checker(const CheckerManager &) {           
\
+    return true;                                                               
\
+  }
 
 // These checker parts are likely to be turned on by default and they don't
 // need the tracking of nullability related information. As an optimization
 // nullability information won't be tracked when the rest are disabled.
-REGISTER_CHECKER(NullabilityBase, false)
-REGISTER_CHECKER(NullPassedToNonnullChecker, false)
-REGISTER_CHECKER(NullReturnedFromNonnullChecker, false)
+REGISTER_CHECKER(NullPassedToNonnull, false)
+REGISTER_CHECKER(NullReturnedFromNonnull, false)
 
-REGISTER_CHECKER(NullableDereferencedChecker, true)
-REGISTER_CHECKER(NullablePassedToNonnullChecker, true)
-REGISTER_CHECKER(NullableReturnedFromNonnullChecker, true)
+REGISTER_CHECKER(NullableDereferenced, true)
+REGISTER_CHECKER(NullablePassedToNonnull, true)
+REGISTER_CHECKER(NullableReturnedFromNonnull, true)
diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c 
b/clang/test/Analysis/analyzer-enabled-checkers.c
index e5d0acb84a039..6d1e5311241d2 100644
--- a/clang/test/Analysis/analyzer-enabled-checkers.c
+++ b/clang/test/Analysis/analyzer-enabled-checkers.c
@@ -33,7 +33,6 @@
 // CHECK-NEXT: core.uninitialized.CapturedBlockVariable
 // CHECK-NEXT: core.uninitialized.UndefReturn
 // CHECK-NEXT: deadcode.DeadStores
-// CHECK-NEXT: nullability.NullabilityBase
 // CHECK-NEXT: nullability.NullPassedToNonnull
 // CHECK-NEXT: nullability.NullReturnedFromNonnull
 // CHECK-NEXT: security.insecureAPI.SecuritySyntaxChecker
diff --git a/clang/test/Analysis/bugfix-124477.m 
b/clang/test/Analysis/bugfix-124477.m
index 80820f4c93444..8bb0196b2f9b8 100644
--- a/clang/test/Analysis/bugfix-124477.m
+++ b/clang/test/Analysis/bugfix-124477.m
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,apiModeling,nullability.NullableDereferenced,nullability.NullabilityBase
 -x objective-c %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,apiModeling,nullability.NullableDereferenced -x 
objective-c %s
 /*
   This test is reduced from a static analyzer crash. The bug causing
   the crash is explained in #124477.  It can only be triggered in some
diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c 
b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c
index d2900c6a42fff..be60870fdb4dc 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c
@@ -41,7 +41,6 @@
 // CHECK-NEXT: core.uninitialized.CapturedBlockVariable
 // CHECK-NEXT: core.uninitialized.UndefReturn
 // CHECK-NEXT: deadcode.DeadStores
-// CHECK-NEXT: nullability.NullabilityBase
 // CHECK-NEXT: nullability.NullPassedToNonnull
 // CHECK-NEXT: nullability.NullReturnedFromNonnull
 // CHECK-NEXT: security.insecureAPI.SecuritySyntaxChecker

From 3ca23ce42044b84507efd96874bea30cec437ff0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com>
Date: Thu, 20 Mar 2025 17:59:50 +0100
Subject: [PATCH 3/4] Use `BugType` parameters for
 `reportBug{,IfInvariantHolds}`

---
 .../Checkers/NullabilityChecker.cpp           | 50 +++++++++----------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 0129f6132e208..1529c3a3b6319 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -169,15 +169,15 @@ class NullabilityChecker
   /// When \p SuppressPath is set to true, no more bugs will be reported on 
this
   /// path by this checker.
   void reportBugIfInvariantHolds(StringRef Msg, ErrorKind Error,
-                                 CheckerPartIdx Idx, ExplodedNode *N,
+                                 const BugType &BT, ExplodedNode *N,
                                  const MemRegion *Region, CheckerContext &C,
                                  const Stmt *ValueExpr = nullptr,
                                  bool SuppressPath = false) const;
 
-  void reportBug(StringRef Msg, ErrorKind Error, CheckerPartIdx Idx,
+  void reportBug(StringRef Msg, ErrorKind Error, const BugType &BT,
                  ExplodedNode *N, const MemRegion *Region, BugReporter &BR,
                  const Stmt *ValueExpr = nullptr) const {
-    auto R = std::make_unique<PathSensitiveBugReport>(BugTypes[Idx], Msg, N);
+    auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
     if (Region) {
       R->markInteresting(Region);
       R->addVisitor<NullabilityBugVisitor>(Region);
@@ -483,7 +483,7 @@ static bool checkInvariantViolation(ProgramStateRef State, 
ExplodedNode *N,
 }
 
 void NullabilityChecker::reportBugIfInvariantHolds(
-    StringRef Msg, ErrorKind Error, CheckerPartIdx Idx, ExplodedNode *N,
+    StringRef Msg, ErrorKind Error, const BugType &BT, ExplodedNode *N,
     const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr,
     bool SuppressPath) const {
   ProgramStateRef OriginalState = N->getState();
@@ -495,7 +495,7 @@ void NullabilityChecker::reportBugIfInvariantHolds(
     N = C.addTransition(OriginalState, N);
   }
 
-  reportBug(Msg, Error, Idx, N, Region, C.getBugReporter(), ValueExpr);
+  reportBug(Msg, Error, BT, N, Region, C.getBugReporter(), ValueExpr);
 }
 
 /// Cleaning up the program state.
@@ -555,14 +555,15 @@ void 
NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const {
     // Do not suppress errors on defensive code paths, because dereferencing
     // a nullable pointer is always an error.
     if (Event.IsDirectDereference)
-      reportBug("Nullable pointer is dereferenced",
-                ErrorKind::NullableDereferenced, NullableDereferencedChecker,
-                Event.SinkNode, Region, BR);
+      reportBug(
+          "Nullable pointer is dereferenced", ErrorKind::NullableDereferenced,
+          BugTypes[NullableDereferencedChecker], Event.SinkNode, Region, BR);
     else {
       reportBug("Nullable pointer is passed to a callee that requires a "
                 "non-null",
-                ErrorKind::NullablePassedToNonnull, 
NullableDereferencedChecker,
-                Event.SinkNode, Region, BR);
+                ErrorKind::NullablePassedToNonnull,
+                BugTypes[NullableDereferencedChecker], Event.SinkNode, Region,
+                BR);
     }
   }
 }
@@ -730,8 +731,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
     OS << " returned from a " << C.getDeclDescription(D) <<
           " that is expected to return a non-null value";
     reportBugIfInvariantHolds(OS.str(), ErrorKind::NilReturnedToNonnull,
-                              NullReturnedFromNonnullChecker, N, nullptr, C,
-                              RetExpr);
+                              BugTypes[NullReturnedFromNonnullChecker], N,
+                              nullptr, C, RetExpr);
     return;
   }
 
@@ -764,8 +765,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
             " that is expected to return a non-null value";
 
       reportBugIfInvariantHolds(OS.str(), ErrorKind::NullableReturnedToNonnull,
-                                NullableReturnedFromNonnullChecker, N, Region,
-                                C);
+                                BugTypes[NullableReturnedFromNonnullChecker], 
N,
+                                Region, C);
     }
     return;
   }
@@ -831,9 +832,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
       OS << " passed to a callee that requires a non-null " << ParamIdx
          << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
       reportBugIfInvariantHolds(OS.str(), ErrorKind::NilPassedToNonnull,
-                                NullPassedToNonnullChecker, N, nullptr, C,
-                                ArgExpr,
-                                /*SuppressPath=*/false);
+                                BugTypes[NullPassedToNonnullChecker], N,
+                                nullptr, C, ArgExpr, /*SuppressPath=*/false);
       return;
     }
 
@@ -858,8 +858,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
         OS << "Nullable pointer is passed to a callee that requires a non-null 
"
            << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
         reportBugIfInvariantHolds(OS.str(), ErrorKind::NullablePassedToNonnull,
-                                  NullablePassedToNonnullChecker, N, Region, C,
-                                  ArgExpr, /*SuppressPath=*/true);
+                                  BugTypes[NullablePassedToNonnullChecker], N,
+                                  Region, C, ArgExpr, /*SuppressPath=*/true);
         return;
       }
       if (isPartEnabled(NullableDereferencedChecker) &&
@@ -867,8 +867,8 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
         ExplodedNode *N = C.addTransition(State);
         reportBugIfInvariantHolds("Nullable pointer is dereferenced",
                                   ErrorKind::NullableDereferenced,
-                                  NullableDereferencedChecker, N, Region, C,
-                                  ArgExpr, /*SuppressPath=*/true);
+                                  BugTypes[NullableDereferencedChecker], N,
+                                  Region, C, ArgExpr, /*SuppressPath=*/true);
         return;
       }
       continue;
@@ -1321,8 +1321,8 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const 
Stmt *S,
     OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null");
     OS << " assigned to a pointer which is expected to have non-null value";
     reportBugIfInvariantHolds(OS.str(), ErrorKind::NilAssignedToNonnull,
-                              NullPassedToNonnullChecker, N, nullptr, C,
-                              ValueStmt);
+                              BugTypes[NullPassedToNonnullChecker], N, nullptr,
+                              C, ValueStmt);
     return;
   }
 
@@ -1355,8 +1355,8 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const 
Stmt *S,
       reportBugIfInvariantHolds("Nullable pointer is assigned to a pointer "
                                 "which is expected to have non-null value",
                                 ErrorKind::NullableAssignedToNonnull,
-                                NullablePassedToNonnullChecker, N, ValueRegion,
-                                C);
+                                BugTypes[NullablePassedToNonnullChecker], N,
+                                ValueRegion, C);
     }
     return;
   }

From d490c74ea866107be4131bd6e694166e702ed8aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com>
Date: Thu, 20 Mar 2025 18:23:31 +0100
Subject: [PATCH 4/4] Special case NoDiagnoseCallsToSystemHeaders as
 group-level option

---
 .../StaticAnalyzer/Checkers/NullabilityChecker.cpp  | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 1529c3a3b6319..54f0d6e4d3486 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -1403,6 +1403,16 @@ void NullabilityChecker::printState(raw_ostream &Out, 
ProgramStateRef State,
   }
 }
 
+// The checker group "nullability" consists of the checkers that are
+// implemented as the parts of the checker class `NullabilityChecker`. These
+// checkers share a checker option "nullability:NoDiagnoseCallsToSystemHeaders"
+// which semantically belongs to the whole group and not just one checker from
+// it. As this is a unique situation (I don't know about any other similar
+// group-level option) there is no mechanism to inject this group name from
+// e.g. Checkers.td, so I'm just hardcoding it here. (These are old stable
+// checkers, I don't think that their name will change.)
+#define CHECKER_GROUP_NAME "nullability"
+
 #define REGISTER_CHECKER(Part, TrackingRequired)                               
\
   void ento::register##Part##Checker(CheckerManager &Mgr) {                    
\
     auto *Checker = Mgr.registerChecker<NullabilityChecker,                    
\
@@ -1411,8 +1421,7 @@ void NullabilityChecker::printState(raw_ostream &Out, 
ProgramStateRef State,
     Checker->NoDiagnoseCallsToSystemHeaders =                                  
\
         Checker->NoDiagnoseCallsToSystemHeaders ||                             
\
         Mgr.getAnalyzerOptions().getCheckerBooleanOption(                      
\
-            Mgr.getCurrentCheckerName(), "NoDiagnoseCallsToSystemHeaders",     
\
-            true);                                                             
\
+            CHECKER_GROUP_NAME, "NoDiagnoseCallsToSystemHeaders", true);       
\
   }                                                                            
\
                                                                                
\
   bool ento::shouldRegister##Part##Checker(const CheckerManager &) {           
\

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to