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
