Author: Benedek Kaibas
Date: 2026-07-12T13:58:52+01:00
New Revision: f99f2a582e947af3f20580fa2674ca0c6bde1b2c

URL: 
https://github.com/llvm/llvm-project/commit/f99f2a582e947af3f20580fa2674ca0c6bde1b2c
DIFF: 
https://github.com/llvm/llvm-project/commit/f99f2a582e947af3f20580fa2674ca0c6bde1b2c.diff

LOG: [analyzer] Implement LifetimeModeling checker and refactor 
UseAfterLifetimeEnd (#205951)

Added: 
    clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
    clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h

Modified: 
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
    clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
    clang/test/Analysis/debug-lifetime-bound.cpp
    clang/test/Analysis/lifetime-bound.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 949e20d1fb98d..0f8b3bb1e1d18 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -795,9 +795,15 @@ def SmartPtrChecker: Checker<"SmartPtr">,
   Dependencies<[SmartPtrModeling]>,
   Documentation<HasDocumentation>;
 
+def LifetimeModeling : Checker<"LifetimeModeling">,
+  HelpText<"Model lifetime annotations for other checkers">,
+  Documentation<NotDocumented>,
+  Hidden;
+
 def UseAfterLifetimeEnd : Checker<"UseAfterLifetimeEnd">,
   HelpText<"Check for uses of references or pointers that "
            "outlive their bound object">,
+  Dependencies<[LifetimeModeling]>,
   Documentation<NotDocumented>;
 
 } // end: "alpha.cplusplus"
@@ -1588,10 +1594,9 @@ def CheckerDocumentationChecker : 
Checker<"CheckerDocumentation">,
   HelpText<"Defines an empty checker callback for all possible handlers.">,
   Documentation<NotDocumented>;
 
-def DebugUseAfterLifetimeEnd : Checker<"DebugUseAfterLifetimeEnd">,
-  HelpText<"Prints the bindings recorded by the UseAfterLifetimeEnd checker. "
-           "Use with clang_analyzer_dumpLifetimeOriginsOf().">,
-  WeakDependencies<[UseAfterLifetimeEnd]>,
+def DebugLifetimeModeling : Checker<"DebugLifetimeModeling">,
+  HelpText<"Dump the set of regions the bound variable originates from">,
+  Dependencies<[LifetimeModeling]>,
   Documentation<NotDocumented>;
 
 } // end "debug"

diff  --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 46c0c36fda736..8f61b7d88e8d2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -55,6 +55,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   IteratorModeling.cpp
   IteratorRangeChecker.cpp
   IvarInvalidationChecker.cpp
+  LifetimeModeling.cpp
   LLVMConventionsChecker.cpp
   LocalizationChecker.cpp
   MacOSKeychainAPIChecker.cpp

diff  --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
new file mode 100644
index 0000000000000..a2f58e0710801
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -0,0 +1,214 @@
+#include "LifetimeModeling.h"
+#include "clang/AST/Attr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *)
+REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SVal, LifetimeSourceSet)
+
+namespace {
+
+class LifetimeModeling : public Checker<check::PostCall, check::DeadSymbols> {
+public:
+  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+                  const char *Sep) const override;
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+};
+
+} // namespace
+
+static bool isDanglingStackSource(const MemRegion *Source,
+                                  ProgramStateRef State, CheckerContext &C) {
+  // FIXME: The checker currently handles stack-region sources. Other
+  // region kinds require separate methodology. For example, heap
+  // regions do not go out of scope at the end of a stack frame, so
+  // in order to detect those type of dangling sources the function
+  // needs to be expanded to an event-driven approach as well.
+  if (const auto *StackSpace =
+          Source->getMemorySpaceAs<StackSpaceRegion>(State)) {
+    const StackFrame *SF = StackSpace->getStackFrame();
+    const StackFrame *CurrentSF = C.getStackFrame();
+    if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
+      return true;
+  }
+  return false;
+}
+
+std::vector<const MemRegion *> 
lifetime_modeling::getDanglingRegionsAfterReturn(
+    SVal Val, ProgramStateRef State, CheckerContext &C) {
+  std::vector<const MemRegion *> Regions;
+  if (auto *SourceSet = State->get<LifetimeBoundMap>(Val)) {
+    for (const MemRegion *Region : *SourceSet) {
+      if (isDanglingStackSource(Region, State, C))
+        Regions.push_back(Region);
+    }
+  }
+  return Regions;
+}
+
+static ProgramStateRef bindSource(ProgramStateRef State, SVal RetVal,
+                                  const MemRegion *Source) {
+  LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>();
+  const LifetimeSourceSet *LSet = State->get<LifetimeBoundMap>(RetVal);
+
+  LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet();
+  Set = F.add(Set, Source);
+  State = State->set<LifetimeBoundMap>(RetVal, Set);
+  return State;
+}
+
+void LifetimeModeling::checkPostCall(const CallEvent &Call,
+                                     CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+
+  const auto *FC = dyn_cast<AnyFunctionCall>(&Call);
+  if (!FC)
+    return;
+
+  const FunctionDecl *FD = FC->getDecl();
+  if (!FD)
+    return;
+
+  SVal RetVal = Call.getReturnValue();
+
+  for (const ParmVarDecl *PVD : FD->parameters()) {
+    if (PVD->hasAttr<LifetimeBoundAttr>()) {
+      unsigned Idx = PVD->getFunctionScopeIndex();
+      SVal Arg = Call.getArgSVal(Idx);
+      if (const MemRegion *ArgValRegion = Arg.getAsRegion())
+        State = bindSource(State, RetVal, ArgValRegion);
+    }
+  }
+
+  const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
+  if (IC && lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
+    if (const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion())
+      State = bindSource(State, RetVal, ThisRegion);
+  }
+  C.addTransition(State);
+}
+
+void LifetimeModeling::checkDeadSymbols(SymbolReaper &SymReaper,
+                                        CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  LifetimeBoundMapTy LBMap = State->get<LifetimeBoundMap>();
+
+  for (SVal Val : llvm::make_first_range(LBMap)) {
+    if (const auto *R = Val.getAsRegion(); R && SymReaper.isLiveRegion(R))
+      continue;
+
+    if (SymbolRef S = Val.getAsSymbol(/*IncludeBaseRegions=*/true);
+        S && SymReaper.isLive(S))
+      continue;
+
+    State = State->remove<LifetimeBoundMap>(Val);
+  }
+  C.addTransition(State);
+}
+
+void LifetimeModeling::printState(raw_ostream &Out, ProgramStateRef State,
+                                  const char *NL, const char *Sep) const {
+  auto LBMap = State->get<LifetimeBoundMap>();
+
+  if (LBMap.isEmpty())
+    return;
+
+  Out << Sep << "LifetimeBound bindings:" << NL;
+  for (auto &&[OriginSym, SourceSet] : LBMap) {
+    for (const auto *Region : SourceSet)
+      Out << " Origin " << OriginSym << " contains Loan " << Region << NL;
+  }
+}
+
+// FIXME: Eventually move the debug checker to its own source file once
+// it has more functionality.
+namespace {
+class DebugLifetimeModeling : public Checker<eval::Call> {
+public:
+  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+  void analyzerDumpLifetimeOriginsOf(const CallEvent &Call,
+                                     CheckerContext &C) const;
+  const BugType BugMsg{this, "DebugLifetimeModeling", "DebugLifetimeModeling"};
+  using FnCheck = void (DebugLifetimeModeling::*)(const CallEvent &Call,
+                                                  CheckerContext &C) const;
+
+  const CallDescriptionMap<FnCheck> Callbacks = {
+      {{CDM::SimpleFunc, {"clang_analyzer_dumpLifetimeOriginsOf"}},
+       &DebugLifetimeModeling::analyzerDumpLifetimeOriginsOf},
+  };
+};
+
+} // namespace
+
+bool DebugLifetimeModeling::evalCall(const CallEvent &Call,
+                                     CheckerContext &C) const {
+  if (!isa_and_nonnull<CallExpr>(Call.getOriginExpr()))
+    return false;
+
+  const FnCheck *Handler = Callbacks.lookup(Call);
+  if (!Handler)
+    return false;
+
+  (this->*(*Handler))(Call, C);
+  return true;
+}
+
+void DebugLifetimeModeling::analyzerDumpLifetimeOriginsOf(
+    const CallEvent &Call, CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+
+  if (Call.getNumArgs() != 1) {
+    if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+      auto BR = std::make_unique<PathSensitiveBugReport>(
+          BugMsg,
+          "clang_analyzer_dumpLifetimeOriginsOf requires exactly 1 argument",
+          N);
+      C.emitReport(std::move(BR));
+    }
+    return;
+  }
+
+  SVal ArgSVal = Call.getArgSVal(0);
+  const LifetimeSourceSet *SourceSet = State->get<LifetimeBoundMap>(ArgSVal);
+
+  if (!SourceSet)
+    return;
+
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+    llvm::SmallVector<std::string> RegionNames =
+        to_vector(map_range(llvm::make_pointee_range(*SourceSet),
+                            std::mem_fn(&MemRegion::getString)));
+    llvm::sort(RegionNames);
+
+    llvm::SmallString<128> Str;
+    llvm::raw_svector_ostream OS(Str);
+    OS << " Origin " << ArgSVal << " bound to ";
+    llvm::interleaveComma(RegionNames, OS);
+    C.emitReport(std::make_unique<PathSensitiveBugReport>(BugMsg, OS.str(), 
N));
+  }
+}
+
+void ento::registerLifetimeModeling(CheckerManager &Mgr) {
+  Mgr.registerChecker<LifetimeModeling>();
+}
+
+bool ento::shouldRegisterLifetimeModeling(const CheckerManager &Mgr) {
+  return true;
+}
+
+void ento::registerDebugLifetimeModeling(CheckerManager &Mgr) {
+  Mgr.registerChecker<DebugLifetimeModeling>();
+}
+
+bool ento::shouldRegisterDebugLifetimeModeling(const CheckerManager &Mgr) {
+  return true;
+}

diff  --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h 
b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h
new file mode 100644
index 0000000000000..e13942eb1856b
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h
@@ -0,0 +1,18 @@
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include <vector>
+
+namespace clang::ento::lifetime_modeling {
+/// Returns the set of lifetime sources bound to \p Source that are dangling
+/// stack regions.
+std::vector<const MemRegion *>
+getDanglingRegionsAfterReturn(SVal Source, ProgramStateRef State,
+                              CheckerContext &C);
+
+} // namespace clang::ento::lifetime_modeling
+
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H

diff  --git a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp 
b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
index db776f1c1c49d..6a2933900c01f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
@@ -1,123 +1,27 @@
-#include "clang/AST/Attr.h"
-#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "LifetimeModeling.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
 using namespace ento;
 
-REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *)
-REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SVal, LifetimeSourceSet)
-
 namespace {
-class UseAfterLifetimeEnd
-    : public Checker<check::PostCall, check::EndFunction, check::DeadSymbols> {
+class UseAfterLifetimeEnd : public Checker<check::EndFunction> {
 public:
-  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
-                  const char *Sep) const override;
-  void reportDanglingSource(const MemRegion *Region, ExplodedNode *N,
+  void reportDanglingSource(const MemRegion *Source, ExplodedNode *N,
                             CheckerContext &C) const;
-  void checkReturnedBorrower(SVal Val, ProgramStateRef State,
-                             CheckerContext &C) const;
   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
-  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
   const BugType BugMsg{this, "UseAfterLifetimeEnd", "LifetimeBound"};
 };
 
 } // namespace
 
-static ProgramStateRef bindValues(ProgramStateRef State, SVal RetVal,
-                                  const MemRegion *Source) {
-  LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>();
-
-  const LifetimeSourceSet *LSet = State->get<LifetimeBoundMap>(RetVal);
-  LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet();
-  Set = F.add(Set, Source);
-  State = State->set<LifetimeBoundMap>(RetVal, Set);
-  return State;
-}
-
-void UseAfterLifetimeEnd::checkPostCall(const CallEvent &Call,
-                                        CheckerContext &C) const {
-  ProgramStateRef State = C.getState();
-
-  const auto *FC = dyn_cast<AnyFunctionCall>(&Call);
-  if (!FC)
-    return;
-
-  const FunctionDecl *FD = FC->getDecl();
-  if (!FD)
-    return;
-
-  SVal RetVal = Call.getReturnValue();
-
-  for (const ParmVarDecl *PVD : FD->parameters()) {
-    if (PVD->hasAttr<LifetimeBoundAttr>()) {
-      unsigned Idx = PVD->getFunctionScopeIndex();
-      SVal Arg = Call.getArgSVal(Idx);
-      if (const MemRegion *ArgValRegion = Arg.getAsRegion())
-        State = bindValues(State, RetVal, ArgValRegion);
-    }
-  }
-
-  if (const auto *IC = dyn_cast<CXXInstanceCall>(&Call)) {
-    if (lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
-      if (const MemRegion *AttrRegion = IC->getCXXThisVal().getAsRegion()) {
-        State = bindValues(State, RetVal, AttrRegion);
-      }
-    }
-  }
-  C.addTransition(State);
-}
-
-static bool hasDanglingSource(const MemRegion *Source, ProgramStateRef State,
-                              CheckerContext &C) {
-  // FIXME: The checker currently handles stack-region sources. Other
-  // region kinds require separate methodology. For example, heap
-  // regions do not go out of scope at the end of a stack frame, so
-  // in order to detect those type of dangling sources the function
-  // needs to be expanded to an event-driven approach as well.
-  if (const auto *StackSpace =
-          Source->getMemorySpaceAs<StackSpaceRegion>(State)) {
-    const StackFrame *SF = StackSpace->getStackFrame();
-    const StackFrame *CurrentSF = C.getStackFrame();
-    if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
-      return true;
-  }
-  return false;
-}
-
-void UseAfterLifetimeEnd::checkReturnedBorrower(SVal Val, ProgramStateRef 
State,
-                                                CheckerContext &C) const {
-  if (auto *SourceSet = State->get<LifetimeBoundMap>(Val)) {
-    ExplodedNode *N = nullptr;
-    for (const MemRegion *Region : *SourceSet) {
-      if (hasDanglingSource(Region, State, C)) {
-        if (!N)
-          N = C.generateNonFatalErrorNode();
-        if (!N)
-          return;
-        reportDanglingSource(Region, N, C);
-      }
-    }
-  }
-}
-
 void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
                                            CheckerContext &C) const {
   if (!RS)
     return;
 
   ProgramStateRef State = C.getState();
-  auto LBMap = State->get<LifetimeBoundMap>();
-
-  if (LBMap.isEmpty())
-    return;
 
   const Expr *RetExpr = RS->getRetValue();
   if (!RetExpr)
@@ -125,122 +29,30 @@ void UseAfterLifetimeEnd::checkEndFunction(const 
ReturnStmt *RS,
 
   RetExpr = RetExpr->IgnoreParens();
   SVal RetVal = C.getSVal(RetExpr);
-  checkReturnedBorrower(RetVal, State, C);
+
+  std::vector<const MemRegion *> RetValRegion =
+      lifetime_modeling::getDanglingRegionsAfterReturn(RetVal, State, C);
+  if (RetValRegion.empty())
+    return;
+
+  if (ExplodedNode *N =
+          C.generateNonFatalErrorNode(State, C.getPredecessor())) {
+    for (const MemRegion *R : RetValRegion)
+      reportDanglingSource(R, N, C);
+  }
 }
 
-void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Region,
+void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Source,
                                                ExplodedNode *N,
                                                CheckerContext &C) const {
   auto BR = std::make_unique<PathSensitiveBugReport>(
       BugMsg,
-      (llvm::Twine("Returning value bound to '") + Region->getString() +
+      (llvm::Twine("Returning value bound to '") + Source->getString() +
        "' that will go out of scope"),
       N);
   C.emitReport(std::move(BR));
 }
 
-void UseAfterLifetimeEnd::checkDeadSymbols(SymbolReaper &SymReaper,
-                                           CheckerContext &C) const {
-  ProgramStateRef State = C.getState();
-  LifetimeBoundMapTy LBMap = State->get<LifetimeBoundMap>();
-
-  for (SVal Val : llvm::make_first_range(LBMap)) {
-    if (const MemRegion *ValRegion = Val.getAsRegion()) {
-      if (!SymReaper.isLiveRegion(ValRegion))
-        State = State->remove<LifetimeBoundMap>(Val);
-    } else if (SymbolRef ValRef =
-                   Val.getAsSymbol(/*IncludeBaseRegions=*/true)) {
-      if (!SymReaper.isLive(ValRef))
-        State = State->remove<LifetimeBoundMap>(Val);
-    }
-  }
-
-  C.addTransition(State);
-}
-
-void UseAfterLifetimeEnd::printState(raw_ostream &Out, ProgramStateRef State,
-                                     const char *NL, const char *Sep) const {
-  auto LBMap = State->get<LifetimeBoundMap>();
-
-  if (LBMap.isEmpty())
-    return;
-
-  Out << Sep << "LifetimeBound bindings:" << NL;
-  for (auto &&[OriginSym, SourceSet] : LBMap) {
-    for (const auto *Region : SourceSet)
-      Out << " Origin " << OriginSym << " contains Loan " << Region << NL;
-  }
-}
-
-namespace {
-class DebugUseAfterLifetimeEnd : public Checker<eval::Call> {
-public:
-  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
-  void analyzerDumpLifetimeOriginsOf(const CallEvent &Call,
-                                     CheckerContext &C) const;
-
-  const BugType BugMsg{this, "DebugUseAfterLifetimeEnd",
-                       "DebugUseAfterLifetimeEnd"};
-  using FnCheck = void (DebugUseAfterLifetimeEnd::*)(const CallEvent &Call,
-                                                     CheckerContext &C) const;
-
-  const CallDescriptionMap<FnCheck> Callbacks = {
-      {{CDM::SimpleFunc, {"clang_analyzer_dumpLifetimeOriginsOf"}},
-       &DebugUseAfterLifetimeEnd::analyzerDumpLifetimeOriginsOf},
-  };
-};
-
-} // namespace
-
-bool DebugUseAfterLifetimeEnd::evalCall(const CallEvent &Call,
-                                        CheckerContext &C) const {
-  const auto *CE = dyn_cast_if_present<CallExpr>(Call.getOriginExpr());
-  if (!CE)
-    return false;
-
-  const FnCheck *Handler = Callbacks.lookup(Call);
-  if (!Handler)
-    return false;
-
-  (this->*(*Handler))(Call, C);
-  return true;
-}
-
-void DebugUseAfterLifetimeEnd::analyzerDumpLifetimeOriginsOf(
-    const CallEvent &Call, CheckerContext &C) const {
-  ProgramStateRef State = C.getState();
-
-  if (Call.getNumArgs() != 1) {
-    if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-      auto BR = std::make_unique<PathSensitiveBugReport>(
-          BugMsg,
-          "clang_analyzer_dumpLifetimeOriginsOf requires exactly 1 argument",
-          N);
-      C.emitReport(std::move(BR));
-    }
-    return;
-  }
-
-  SVal ArgSVal = Call.getArgSVal(0);
-  const LifetimeSourceSet *SourceSet = State->get<LifetimeBoundMap>(ArgSVal);
-
-  if (!SourceSet)
-    return;
-
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-    llvm::SmallVector<std::string> RegionNames =
-        to_vector(map_range(llvm::make_pointee_range(*SourceSet),
-                            std::mem_fn(&MemRegion::getString)));
-    llvm::sort(RegionNames);
-
-    llvm::SmallString<128> Str;
-    llvm::raw_svector_ostream OS(Str);
-    OS << " Origin " << ArgSVal << " bound to ";
-    llvm::interleaveComma(RegionNames, OS);
-    C.emitReport(std::make_unique<PathSensitiveBugReport>(BugMsg, OS.str(), 
N));
-  }
-}
-
 void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
   Mgr.registerChecker<UseAfterLifetimeEnd>();
 }
@@ -248,11 +60,3 @@ void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) 
{
 bool ento::shouldRegisterUseAfterLifetimeEnd(const CheckerManager &Mgr) {
   return true;
 }
-
-void ento::registerDebugUseAfterLifetimeEnd(CheckerManager &Mgr) {
-  Mgr.registerChecker<DebugUseAfterLifetimeEnd>();
-}
-
-bool ento::shouldRegisterDebugUseAfterLifetimeEnd(const CheckerManager &Mgr) {
-  return true;
-}

diff  --git a/clang/test/Analysis/debug-lifetime-bound.cpp 
b/clang/test/Analysis/debug-lifetime-bound.cpp
index 8ef704195dcc6..b52d23c88071d 100644
--- a/clang/test/Analysis/debug-lifetime-bound.cpp
+++ b/clang/test/Analysis/debug-lifetime-bound.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd
 -verify %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling
 -verify %s
 
 // expected-no-diagnostics
 

diff  --git a/clang/test/Analysis/lifetime-bound.cpp 
b/clang/test/Analysis/lifetime-bound.cpp
index e99299b5d03bf..f8519b76798fd 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd
 \
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling
 \
 // RUN:   -analyzer-config cfg-lifetime=true -verify %s
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd
 \
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling
 \
 // RUN:   -analyzer-config c++-container-inlining=false -analyzer-config 
cfg-lifetime=true -verify %s
 
 struct A {};


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

Reply via email to