Author: DEBADRIBASAK
Date: 2025-12-22T17:17:18Z
New Revision: bbd60c05231075c420e6c5db630d89eda3cb171b

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

LOG: [LifetimeSafety] Add missing origins stats for lifetime analysis  (#166568)

This PR adds the implementation for printing missing origin stats for
lifetime analysis.

**Purpose:**

This capability is added to track the expression types with missing
origin. While retrieving the origins from origin manager, some
expressions show missing origins. Currently these are created on the fly
using getOrCreate function. For analysing the coverage of the check, it
will be necessary to see what kind of expressions have a missing origin.
It prints the counts in this form: `QualType : count` and `StmtClassName
: count`.

**Approach:**

1. The signature of the runLifetimeAnalysis function is changed to
return the LifetimeAnalysis object which will be used to get the origin
manager which can be used for finding the count of missing origins.
2. The count of missing origins is kept in origin manager while the CFG
is visited as part of the analysis.

Example output:

For the file llvm-project/llvm/lib/Demangle/Demangle.cpp:

```
*** LifetimeSafety Missing Origin per QualType: (QualType : count) :

value_type : 1
char * : 3


*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :

BinaryOperator : 3
UnaryOperator : 1

Total missing origins: 4
```

Added: 
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h
    clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp
    clang/test/Sema/warn-lifetime-safety-missing-origin-stats.cpp

Modified: 
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
    clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
    clang/include/clang/Sema/AnalysisBasedWarnings.h
    clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
    clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
    clang/lib/Analysis/LifetimeSafety/Origins.cpp
    clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 53caaa40650e2..9c91355355233 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -21,8 +21,10 @@
 #define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
 
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 
 namespace clang::lifetimes {
@@ -62,9 +64,14 @@ class LifetimeSafetyReporter {
 
 /// The main entry point for the analysis.
 void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
-                               LifetimeSafetyReporter *Reporter);
+                               LifetimeSafetyReporter *Reporter,
+                               LifetimeSafetyStats &Stats, bool CollectStats);
 
 namespace internal {
+
+void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
+                          LifetimeSafetyStats &Stats);
+
 /// An object to hold the factories for immutable collections, ensuring
 /// that all created states share the same underlying memory management.
 struct LifetimeFactory {

diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h
new file mode 100644
index 0000000000000..0fae03000c7c1
--- /dev/null
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h
@@ -0,0 +1,36 @@
+//===- LifetimeStats.h - Lifetime Safety Statistics -------------*- C++-* 
-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the data structures and utility function for collection 
of
+// statistics related to Lifetime Safety analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H
+
+#include "clang/AST/TypeBase.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang::lifetimes {
+/// A structure to hold the statistics related to LifetimeAnalysis.
+/// These are accumulated across all analyzed functions and printed
+/// when -print-stats is enabled.
+struct LifetimeSafetyStats {
+  /// A map from `StmtClassName` to their missing origin counts.
+  llvm::StringMap<unsigned> ExprStmtClassToMissingOriginCount;
+  /// A map from `QualType` to their missing origin counts.
+  llvm::DenseMap<const clang::Type *, unsigned> ExprTypeToMissingOriginCount;
+};
+
+/// Utility function to print missing origin stats.
+void printStats(const LifetimeSafetyStats &Stats);
+} // namespace clang::lifetimes
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H

diff  --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index d6246183a5ca7..690faae996f0e 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -17,7 +17,9 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/TypeBase.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
+#include "llvm/Support/raw_ostream.h"
 
 namespace clang::lifetimes::internal {
 
@@ -150,6 +152,9 @@ class OriginManager {
 
   void dump(OriginID OID, llvm::raw_ostream &OS) const;
 
+  /// Collects statistics about expressions that lack associated origins.
+  void collectMissingOrigins(Stmt &FunctionBody, LifetimeSafetyStats &LSStats);
+
 private:
   OriginID getNextOriginID() { return NextOriginID++; }
 

diff  --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h 
b/clang/include/clang/Sema/AnalysisBasedWarnings.h
index 20a2030f56034..0ed61e56825be 100644
--- a/clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -14,9 +14,8 @@
 #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
 
 #include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Sema/ScopeInfo.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/MapVector.h"
 #include <memory>
 
 namespace clang {
@@ -101,6 +100,11 @@ class AnalysisBasedWarnings {
   /// a single function.
   unsigned MaxUninitAnalysisBlockVisitsPerFunction;
 
+  /// Statistics collected during lifetime safety analysis.
+  /// These are accumulated across all analyzed functions and printed
+  /// when -print-stats is enabled.
+  clang::lifetimes::LifetimeSafetyStats LSStats;
+
   /// @}
 
 public:

diff  --git a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt 
b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
index 5874e8405baf6..e5876e747610a 100644
--- a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
+++ b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
@@ -5,6 +5,7 @@ add_clang_library(clangAnalysisLifetimeSafety
   LifetimeAnnotations.cpp
   LifetimeSafety.cpp
   LiveOrigins.cpp
+  LifetimeStats.cpp
   Loans.cpp
   LoanPropagation.cpp
   Origins.cpp

diff  --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index c0fa640a8ba66..be0d405bd3086 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -18,8 +18,10 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Checker.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
 #include "llvm/ADT/FoldingSet.h"
@@ -90,11 +92,22 @@ void LifetimeSafetyAnalysis::run() {
 
   runLifetimeChecker(*LoanPropagation, *LiveOrigins, *FactMgr, AC, Reporter);
 }
+
+void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
+                          LifetimeSafetyStats &Stats) {
+  Stmt *FunctionBody = AC.getBody();
+  if (FunctionBody == nullptr)
+    return;
+  OM.collectMissingOrigins(*FunctionBody, Stats);
+}
 } // namespace internal
 
 void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
-                               LifetimeSafetyReporter *Reporter) {
+                               LifetimeSafetyReporter *Reporter,
+                               LifetimeSafetyStats &Stats, bool CollectStats) {
   internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
   Analysis.run();
+  if (CollectStats)
+    collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
 }
 } // namespace clang::lifetimes

diff  --git a/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp
new file mode 100644
index 0000000000000..7e568597451ab
--- /dev/null
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp
@@ -0,0 +1,38 @@
+//===- LifetimeStats.cpp - Lifetime Safety Statistics -*------------ 
C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the data structures and utility function for collection of
+// staticstics related to Lifetimesafety analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
+#include "clang/AST/TypeBase.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang::lifetimes {
+void printStats(const LifetimeSafetyStats &Stats) {
+  llvm::errs() << "\n*** LifetimeSafety Missing Origin per QualType: "
+                  "(QualType : count) :\n\n";
+  unsigned TotalMissingOrigins = 0;
+  for (const auto &[ExprType, MissingOriginCount] :
+       Stats.ExprTypeToMissingOriginCount) {
+    QualType QT = QualType(ExprType, 0);
+    llvm::errs() << QT.getAsString() << " : " << MissingOriginCount << '\n';
+    TotalMissingOrigins += MissingOriginCount;
+  }
+  llvm::errs() << "\n\n*** LifetimeSafety Missing Origin per StmtClassName: "
+                  "(StmtClassName : count) :\n\n";
+  for (const auto &[ExprStmtClassName, MissingOriginCount] :
+       Stats.ExprStmtClassToMissingOriginCount) {
+    llvm::errs() << ExprStmtClassName << " : " << MissingOriginCount << '\n';
+  }
+  llvm::errs() << "\nTotal missing origins: " << TotalMissingOrigins << "\n";
+  llvm::errs() << "\n****************************************\n";
+}
+} // namespace clang::lifetimes

diff  --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp 
b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index b2f1af3d8d7c3..2c1deac03d24b 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -11,10 +11,42 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeBase.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
+#include "llvm/ADT/StringMap.h"
 
 namespace clang::lifetimes::internal {
+namespace {
+/// A utility class to traverse the function body in the analysis
+/// context and collect the count of expressions with missing origins.
+class MissingOriginCollector
+    : public RecursiveASTVisitor<MissingOriginCollector> {
+public:
+  MissingOriginCollector(
+      const llvm::DenseMap<const clang::Expr *, OriginList *> 
&ExprToOriginList,
+      LifetimeSafetyStats &LSStats)
+      : ExprToOriginList(ExprToOriginList), LSStats(LSStats) {}
+  bool VisitExpr(Expr *E) {
+    if (!hasOrigins(E))
+      return true;
+    // Check if we have an origin for this expression.
+    if (!ExprToOriginList.contains(E)) {
+      // No origin found: count this as missing origin.
+      LSStats.ExprTypeToMissingOriginCount[E->getType().getTypePtr()]++;
+      LSStats.ExprStmtClassToMissingOriginCount[std::string(
+          E->getStmtClassName())]++;
+    }
+    return true;
+  }
+
+private:
+  const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList;
+  LifetimeSafetyStats &LSStats;
+};
+} // namespace
 
 bool hasOrigins(QualType QT) {
   return QT->isPointerOrReferenceType() || isGslPointerType(QT);
@@ -157,4 +189,10 @@ const Origin &OriginManager::getOrigin(OriginID ID) const {
   return AllOrigins[ID.Value];
 }
 
+void OriginManager::collectMissingOrigins(Stmt &FunctionBody,
+                                          LifetimeSafetyStats &LSStats) {
+  MissingOriginCollector Collector(this->ExprToList, LSStats);
+  Collector.TraverseStmt(const_cast<Stmt *>(&FunctionBody));
+}
+
 } // namespace clang::lifetimes::internal

diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp 
b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 9dcae980def25..7b08648080710 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3135,7 +3135,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
   if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
     if (AC.getCFG()) {
       lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
-      lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter);
+      lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, 
LSStats,
+                                           S.CollectStats);
     }
   }
   // Check for violations of "called once" parameter properties.
@@ -3231,4 +3232,5 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() 
const {
                << " average block visits per function.\n"
                << "  " << MaxUninitAnalysisBlockVisitsPerFunction
                << " max block visits per function.\n";
+  clang::lifetimes::printStats(LSStats);
 }

diff  --git a/clang/test/Sema/warn-lifetime-safety-missing-origin-stats.cpp 
b/clang/test/Sema/warn-lifetime-safety-missing-origin-stats.cpp
new file mode 100644
index 0000000000000..446bbe0e06b13
--- /dev/null
+++ b/clang/test/Sema/warn-lifetime-safety-missing-origin-stats.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -print-stats -fexperimental-lifetime-safety 
-Wexperimental-lifetime-safety %s 2>&1 | FileCheck %s
+
+
+// CHECK: *** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+// CHECK: *** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName 
: count) :


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

Reply via email to