https://github.com/DEBADRIBASAK updated https://github.com/llvm/llvm-project/pull/166568
>From fd8693c51af7d9f91be0926f4150e77c39e2dba4 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 5 Nov 2025 14:07:42 +0000 Subject: [PATCH 1/7] Adding the lifetime stats collection logic to AnalysisBasedWarnings --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 15 +++++++--- .../Analyses/LifetimeSafety/Origins.h | 6 ++++ .../clang/Sema/AnalysisBasedWarnings.h | 9 ++++++ .../LifetimeSafety/LifetimeSafety.cpp | 13 +++++--- clang/lib/Analysis/LifetimeSafety/Origins.cpp | 18 +++++++++++ clang/lib/Sema/AnalysisBasedWarnings.cpp | 30 +++++++++++++++++-- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 91ffbb169f947..eb532bc8be3a7 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -23,7 +23,11 @@ #include "clang/Analysis/Analyses/LifetimeSafety/Facts.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 "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" +#include <string> namespace clang::lifetimes { @@ -44,10 +48,6 @@ class LifetimeSafetyReporter { Confidence Confidence) {} }; -/// The main entry point for the analysis. -void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter); - namespace internal { /// An object to hold the factories for immutable collections, ensuring /// that all created states share the same underlying memory management. @@ -60,6 +60,7 @@ struct LifetimeFactory { /// Running the lifetime safety analysis and querying its results. It /// encapsulates the various dataflow analyses. class LifetimeSafetyAnalysis { + public: LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter); @@ -82,6 +83,12 @@ class LifetimeSafetyAnalysis { std::unique_ptr<LoanPropagationAnalysis> LoanPropagation; }; } // namespace internal + +/// The main entry point for the analysis. +std::unique_ptr<internal::LifetimeSafetyAnalysis> +runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter); + } // namespace clang::lifetimes #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h index ba138b078b379..3f8c8a4d7ce9b 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h @@ -16,7 +16,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeBase.h" #include "clang/Analysis/Analyses/LifetimeSafety/Utils.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" namespace clang::lifetimes::internal { @@ -76,6 +79,8 @@ class OriginManager { void dump(OriginID OID, llvm::raw_ostream &OS) const; + const llvm::StringMap<int> getMissingOrigins() const; + private: OriginID getNextOriginID() { return NextOriginID++; } @@ -85,6 +90,7 @@ class OriginManager { llvm::SmallVector<Origin> AllOrigins; llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID; llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID; + llvm::StringMap<unsigned> ExprTypeToMissingOriginCount; }; } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h index 4103c3f006a8f..604039ef61cb7 100644 --- a/clang/include/clang/Sema/AnalysisBasedWarnings.h +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -14,7 +14,10 @@ #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H #include "clang/AST/Decl.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include <memory> namespace clang { @@ -95,6 +98,9 @@ class AnalysisBasedWarnings { /// a single function. unsigned MaxUninitAnalysisBlockVisitsPerFunction; + /// Map from expressions missing origin in OriginManager to their counts. + llvm::StringMap<unsigned> MissingOriginCount; + /// @} public: @@ -116,6 +122,9 @@ class AnalysisBasedWarnings { Policy &getPolicyOverrides() { return PolicyOverrides; } void PrintStats() const; + + void FindMissingOrigins(AnalysisDeclContext &AC, + clang::lifetimes::internal::FactManager &FactMgr); }; } // namespace sema diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 00c7ed90503e7..d183ce976f946 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -23,9 +23,11 @@ #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/raw_ostream.h" #include <memory> namespace clang::lifetimes { @@ -69,9 +71,12 @@ void LifetimeSafetyAnalysis::run() { } } // namespace internal -void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter) { - internal::LifetimeSafetyAnalysis Analysis(AC, Reporter); - Analysis.run(); +std::unique_ptr<internal::LifetimeSafetyAnalysis> +runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter) { + std::unique_ptr<internal::LifetimeSafetyAnalysis> Analysis = + std::make_unique<internal::LifetimeSafetyAnalysis>(AC, Reporter); + Analysis->run(); + return Analysis; } } // namespace clang::lifetimes diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index ea51a75324e06..453abf48261c2 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -7,6 +7,9 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeBase.h" +#include "llvm/ADT/StringMap.h" namespace clang::lifetimes::internal { @@ -22,6 +25,10 @@ void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const { OS << ")"; } +const llvm::StringMap<unsigned> OriginManager::getMissingOrigins() const { + return ExprTypeToMissingOriginCount; +} + Origin &OriginManager::addOrigin(OriginID ID, const clang::ValueDecl &D) { AllOrigins.emplace_back(ID, &D); return AllOrigins.back(); @@ -37,6 +44,17 @@ OriginID OriginManager::get(const Expr &E) { auto It = ExprToOriginID.find(&E); if (It != ExprToOriginID.end()) return It->second; + + // if the expression has no specific origin, increment the missing origin + // counter. + std::string ExprStr(E.getStmtClassName()); + ExprStr = ExprStr + "<" + E.getType().getAsString() + ">"; + auto CountIt = ExprTypeToMissingOriginCount.find(ExprStr); + if (CountIt == ExprTypeToMissingOriginCount.end()) { + ExprTypeToMissingOriginCount[ExprStr] = 1; + } else { + CountIt->second++; + } // If the expression itself has no specific origin, and it's a reference // to a declaration, its origin is that of the declaration it refers to. // For pointer types, where we don't pre-emptively create an origin for the diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 140b709dbb651..9160939a85735 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -29,7 +29,9 @@ #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/CalledOnceCheck.h" #include "clang/Analysis/Analyses/Consumed.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" +#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/UninitializedValues.h" @@ -52,7 +54,9 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <deque> #include <iterator> @@ -3065,7 +3069,11 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); - lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter); + std::unique_ptr<clang::lifetimes::internal::LifetimeSafetyAnalysis> + Analysis = + lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter); + if (S.CollectStats) + FindMissingOrigins(AC, Analysis->getFactManager()); } } // Check for violations of "called once" parameter properties. @@ -3131,9 +3139,27 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } } +void clang::sema::AnalysisBasedWarnings::FindMissingOrigins( + AnalysisDeclContext &AC, lifetimes::internal::FactManager &FactMgr) { + if (AC.getCFG()) { + for (const auto &[expr, count] : + FactMgr.getOriginMgr().getMissingOrigins()) { + MissingOriginCount[expr] += count; + } + } +} + void clang::sema::AnalysisBasedWarnings::PrintStats() const { + llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " + "(expression_type : count) :\n"; + unsigned totalMissingOrigins = 0; + for (const auto &[expr, count] : MissingOriginCount) { + llvm::errs() << expr << " : " << count << '\n'; + totalMissingOrigins += count; + } + llvm::errs() << "Total missing origins: " << totalMissingOrigins << "\n"; + llvm::errs() << "****************************************\n"; llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; - unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; >From 3ff81d6435d7da0b4c86459fd71344cf2008acca Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 5 Nov 2025 14:22:48 +0000 Subject: [PATCH 2/7] Correcting the signature of getMissingOrigins --- .../include/clang/Analysis/Analyses/LifetimeSafety/Origins.h | 2 +- clang/lib/Sema/AnalysisBasedWarnings.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h index 3f8c8a4d7ce9b..26686a63e9204 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h @@ -79,7 +79,7 @@ class OriginManager { void dump(OriginID OID, llvm::raw_ostream &OS) const; - const llvm::StringMap<int> getMissingOrigins() const; + const llvm::StringMap<unsigned> getMissingOrigins() const; private: OriginID getNextOriginID() { return NextOriginID++; } diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 9160939a85735..77d2013ff3a93 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3151,14 +3151,14 @@ void clang::sema::AnalysisBasedWarnings::FindMissingOrigins( void clang::sema::AnalysisBasedWarnings::PrintStats() const { llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " - "(expression_type : count) :\n"; + "(expression_type : count) :\n\n"; unsigned totalMissingOrigins = 0; for (const auto &[expr, count] : MissingOriginCount) { llvm::errs() << expr << " : " << count << '\n'; totalMissingOrigins += count; } llvm::errs() << "Total missing origins: " << totalMissingOrigins << "\n"; - llvm::errs() << "****************************************\n"; + llvm::errs() << "\n****************************************\n"; llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = >From 499d3b07efd16cce82960ad2c7db5164e9d97b35 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Tue, 18 Nov 2025 13:53:55 +0000 Subject: [PATCH 3/7] Adding a LifetimeSafetyStats struct to keep track of missing origins and change the signature of runLifetimeSafetyAnalysis to not return the analysis object --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 15 ++++++++-- .../clang/Sema/AnalysisBasedWarnings.h | 7 ++--- .../LifetimeSafety/LifetimeSafety.cpp | 23 ++++++++++++--- clang/lib/Sema/AnalysisBasedWarnings.cpp | 28 +++---------------- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index eb532bc8be3a7..cbbaa6e1884ee 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -38,6 +38,12 @@ enum class Confidence : uint8_t { Definite // Reported as a definite error (-Wlifetime-safety-permissive) }; +/// A structure to hold the statistics related to LifetimeAnalysis. +/// Curently it holds only the missing origin details. +struct LifetimeSafetyStats { + llvm::StringMap<unsigned> MissingOriginCount; +}; + class LifetimeSafetyReporter { public: LifetimeSafetyReporter() = default; @@ -84,10 +90,13 @@ class LifetimeSafetyAnalysis { }; } // namespace internal +// utility function to print missing origin stats. +void PrintStats(const LifetimeSafetyStats &Stats); + /// The main entry point for the analysis. -std::unique_ptr<internal::LifetimeSafetyAnalysis> -runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter); +void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter, + LifetimeSafetyStats &Stats, bool CollectStats); } // namespace clang::lifetimes diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h index 604039ef61cb7..eb334fd0e6390 100644 --- a/clang/include/clang/Sema/AnalysisBasedWarnings.h +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -15,8 +15,10 @@ #include "clang/AST/Decl.h" #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringMap.h" #include <memory> @@ -99,7 +101,7 @@ class AnalysisBasedWarnings { unsigned MaxUninitAnalysisBlockVisitsPerFunction; /// Map from expressions missing origin in OriginManager to their counts. - llvm::StringMap<unsigned> MissingOriginCount; + clang::lifetimes::LifetimeSafetyStats LSStats; /// @} @@ -122,9 +124,6 @@ class AnalysisBasedWarnings { Policy &getPolicyOverrides() { return PolicyOverrides; } void PrintStats() const; - - void FindMissingOrigins(AnalysisDeclContext &AC, - clang::lifetimes::internal::FactManager &FactMgr); }; } // namespace sema diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index d183ce976f946..5935c5fd6df93 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -71,12 +71,27 @@ void LifetimeSafetyAnalysis::run() { } } // namespace internal -std::unique_ptr<internal::LifetimeSafetyAnalysis> -runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter) { +void PrintStats(const LifetimeSafetyStats &Stats) { + llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " + "(expression_type : count) :\n\n"; + unsigned totalMissingOrigins = 0; + for (const auto &[expr, count] : Stats.MissingOriginCount) { + llvm::errs() << expr << " : " << count << '\n'; + totalMissingOrigins += count; + } + llvm::errs() << "Total missing origins: " << totalMissingOrigins << "\n"; + llvm::errs() << "\n****************************************\n"; +} + +void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter, + LifetimeSafetyStats &Stats, bool CollectStats) { std::unique_ptr<internal::LifetimeSafetyAnalysis> Analysis = std::make_unique<internal::LifetimeSafetyAnalysis>(AC, Reporter); Analysis->run(); - return Analysis; + for (const auto &[expr, count] : + Analysis->getFactManager().getOriginMgr().getMissingOrigins()) { + Stats.MissingOriginCount[expr] += count; + } } } // namespace clang::lifetimes diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 77d2013ff3a93..e2ad6eb209059 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3069,11 +3069,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { if (AC.getCFG()) { lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S); - std::unique_ptr<clang::lifetimes::internal::LifetimeSafetyAnalysis> - Analysis = - lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter); - if (S.CollectStats) - FindMissingOrigins(AC, Analysis->getFactManager()); + lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, LSStats, + S.CollectStats); } } // Check for violations of "called once" parameter properties. @@ -3139,26 +3136,9 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } } -void clang::sema::AnalysisBasedWarnings::FindMissingOrigins( - AnalysisDeclContext &AC, lifetimes::internal::FactManager &FactMgr) { - if (AC.getCFG()) { - for (const auto &[expr, count] : - FactMgr.getOriginMgr().getMissingOrigins()) { - MissingOriginCount[expr] += count; - } - } -} - void clang::sema::AnalysisBasedWarnings::PrintStats() const { - llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " - "(expression_type : count) :\n\n"; - unsigned totalMissingOrigins = 0; - for (const auto &[expr, count] : MissingOriginCount) { - llvm::errs() << expr << " : " << count << '\n'; - totalMissingOrigins += count; - } - llvm::errs() << "Total missing origins: " << totalMissingOrigins << "\n"; - llvm::errs() << "\n****************************************\n"; + + clang::lifetimes::PrintStats(LSStats); llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = >From 83417784cd7c3870bf82fef500be01db79eaef6f Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 26 Nov 2025 05:32:39 +0000 Subject: [PATCH 4/7] Moving the missing origin calculation logic after lifetime analysis using an AST visitor --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 20 +++--- .../Analyses/LifetimeSafety/Origins.h | 28 +++++++- .../clang/Sema/AnalysisBasedWarnings.h | 4 +- .../LifetimeSafety/LifetimeSafety.cpp | 17 +++-- clang/lib/Analysis/LifetimeSafety/Origins.cpp | 70 +++++++++++++++---- clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 +- 6 files changed, 112 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index cbbaa6e1884ee..6c091fa6f6d6b 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -54,7 +54,19 @@ class LifetimeSafetyReporter { Confidence Confidence) {} }; +// utility function to print missing origin stats. +void printStats(const LifetimeSafetyStats &Stats); + +/// The main entry point for the analysis. +void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + 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 { @@ -90,14 +102,6 @@ class LifetimeSafetyAnalysis { }; } // namespace internal -// utility function to print missing origin stats. -void PrintStats(const LifetimeSafetyStats &Stats); - -/// The main entry point for the analysis. -void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, - LifetimeSafetyReporter *Reporter, - LifetimeSafetyStats &Stats, bool CollectStats); - } // namespace clang::lifetimes #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h index 5c0c73f9b321c..baf9bb9be8439 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h @@ -16,11 +16,17 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeBase.h" #include "clang/Analysis/Analyses/LifetimeSafety/Utils.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/raw_ostream.h" +namespace clang::lifetimes { + +struct LifetimeSafetyStats; +} // namespace clang::lifetimes + namespace clang::lifetimes::internal { using OriginID = utils::ID<struct OriginTag>; @@ -81,7 +87,10 @@ class OriginManager { void dump(OriginID OID, llvm::raw_ostream &OS) const; - const llvm::StringMap<unsigned> getMissingOrigins() const; + const llvm::DenseMap<const clang::Expr *, OriginID> & + getExprToOriginId() const; + + void collectMissingOrigins(Stmt *FunctionBody, LifetimeSafetyStats &LSStats); private: OriginID getNextOriginID() { return NextOriginID++; } @@ -92,8 +101,23 @@ class OriginManager { llvm::SmallVector<Origin> AllOrigins; llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID; llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID; - llvm::StringMap<unsigned> ExprTypeToMissingOriginCount; }; + +/// An 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 OriginManager &om, + llvm::StringMap<unsigned> &MissingOriginCount) + : OM(om), MissingOriginCount(MissingOriginCount) {} + bool VisitExpr(Expr *E); + +private: + const OriginManager &OM; + llvm::StringMap<unsigned> &MissingOriginCount; +}; + } // namespace clang::lifetimes::internal #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_ORIGINS_H diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h index 221ee60483546..d17486a66b297 100644 --- a/clang/include/clang/Sema/AnalysisBasedWarnings.h +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -105,7 +105,9 @@ class AnalysisBasedWarnings { /// a single function. unsigned MaxUninitAnalysisBlockVisitsPerFunction; - /// Map from expressions missing origin in OriginManager to their counts. + /// Statistics collected during lifetime safety analysis. + /// These are accumulated across all analyzed functions and printed + /// when -print-stats is enabled. clang::lifetimes::LifetimeSafetyStats LSStats; /// @} diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index b38640b1c0642..cc0acbd42df39 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -20,6 +20,7 @@ #include "clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.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" @@ -70,9 +71,17 @@ void LifetimeSafetyAnalysis::run() { runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter); } + +void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM, + LifetimeSafetyStats &Stats) { + if (!AC.getBody()) + return; + Stmt *FunctionBody = AC.getBody(); + OM.collectMissingOrigins(FunctionBody, Stats); +} } // namespace internal -void PrintStats(const LifetimeSafetyStats &Stats) { +void printStats(const LifetimeSafetyStats &Stats) { llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " "(expression_type : count) :\n\n"; unsigned totalMissingOrigins = 0; @@ -90,9 +99,7 @@ void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, std::unique_ptr<internal::LifetimeSafetyAnalysis> Analysis = std::make_unique<internal::LifetimeSafetyAnalysis>(AC, Reporter); Analysis->run(); - for (const auto &[expr, count] : - Analysis->getFactManager().getOriginMgr().getMissingOrigins()) { - Stats.MissingOriginCount[expr] += count; - } + if (CollectStats) + collectLifetimeStats(AC, Analysis->getFactManager().getOriginMgr(), Stats); } } // namespace clang::lifetimes diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index 96750d9f94990..0f0b20305fbf2 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -9,10 +9,31 @@ #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeBase.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" #include "llvm/ADT/StringMap.h" namespace clang::lifetimes::internal { +static bool isGslPointerType(QualType QT) { + if (const auto *RD = QT->getAsCXXRecordDecl()) { + // We need to check the template definition for specializations. + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + return CTSD->getSpecializedTemplate() + ->getTemplatedDecl() + ->hasAttr<PointerAttr>(); + return RD->hasAttr<PointerAttr>(); + } + return false; +} + +static bool isPointerType(QualType QT) { + return QT->isPointerOrReferenceType() || isGslPointerType(QT); +} +// Check if a type has an origin. +static bool hasOrigin(const Expr *E) { + return E->isGLValue() || isPointerType(E->getType()); +} + void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const { OS << OID << " ("; Origin O = getOrigin(OID); @@ -25,10 +46,6 @@ void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const { OS << ")"; } -const llvm::StringMap<unsigned> OriginManager::getMissingOrigins() const { - return ExprTypeToMissingOriginCount; -} - Origin &OriginManager::addOrigin(OriginID ID, const clang::ValueDecl &D) { AllOrigins.emplace_back(ID, &D); return AllOrigins.back(); @@ -49,14 +66,14 @@ OriginID OriginManager::get(const Expr &E) { // if the expression has no specific origin, increment the missing origin // counter. - std::string ExprStr(E.getStmtClassName()); - ExprStr = ExprStr + "<" + E.getType().getAsString() + ">"; - auto CountIt = ExprTypeToMissingOriginCount.find(ExprStr); - if (CountIt == ExprTypeToMissingOriginCount.end()) { - ExprTypeToMissingOriginCount[ExprStr] = 1; - } else { - CountIt->second++; - } + // std::string ExprStr(E.getStmtClassName()); + // ExprStr = ExprStr + "<" + E.getType().getAsString() + ">"; + // auto CountIt = ExprTypeToMissingOriginCount.find(ExprStr); + // if (CountIt == ExprTypeToMissingOriginCount.end()) + // ExprTypeToMissingOriginCount[ExprStr] = 1; + // else + // CountIt->second++; + // If the expression itself has no specific origin, and it's a reference // to a declaration, its origin is that of the declaration it refers to. // For pointer types, where we don't pre-emptively create an origin for the @@ -106,4 +123,33 @@ OriginID OriginManager::getOrCreate(const ValueDecl &D) { return NewID; } +const llvm::DenseMap<const clang::Expr *, OriginID> & +OriginManager::getExprToOriginId() const { + return ExprToOriginID; +} + +void OriginManager::collectMissingOrigins(Stmt *FunctionBody, + LifetimeSafetyStats &LSStats) { + if (!FunctionBody) + return; + + MissingOriginCollector Collector(*this, LSStats.MissingOriginCount); + Collector.TraverseStmt(const_cast<Stmt *>(FunctionBody)); +} + +bool MissingOriginCollector::VisitExpr(Expr *E) { + if (!hasOrigin(E)) + return true; + // Check if we have an origin for this expression + const auto &ExprToOriginId = OM.getExprToOriginId(); + auto It = ExprToOriginId.find(E); + if (It == ExprToOriginId.end()) { + // No origin found - count this as missing + std::string ExprStr = std::string(E->getStmtClassName()) + "<" + + E->getType().getAsString() + ">"; + MissingOriginCount[ExprStr]++; + } + return true; +} + } // namespace clang::lifetimes::internal diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 2ad2684c7f292..ae549f6b4f877 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -54,7 +54,6 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -3165,7 +3164,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( void clang::sema::AnalysisBasedWarnings::PrintStats() const { - clang::lifetimes::PrintStats(LSStats); llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = @@ -3194,4 +3192,5 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const { << " average block visits per function.\n" << " " << MaxUninitAnalysisBlockVisitsPerFunction << " max block visits per function.\n"; + clang::lifetimes::printStats(LSStats); } >From 56b2dd9315a686e6aa05e9afc353100f02ded2be Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Wed, 26 Nov 2025 05:36:55 +0000 Subject: [PATCH 5/7] Removing an outdated comment --- clang/lib/Analysis/LifetimeSafety/Origins.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index 0f0b20305fbf2..03efc27e9d959 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -64,16 +64,6 @@ OriginID OriginManager::get(const Expr &E) { if (It != ExprToOriginID.end()) return It->second; - // if the expression has no specific origin, increment the missing origin - // counter. - // std::string ExprStr(E.getStmtClassName()); - // ExprStr = ExprStr + "<" + E.getType().getAsString() + ">"; - // auto CountIt = ExprTypeToMissingOriginCount.find(ExprStr); - // if (CountIt == ExprTypeToMissingOriginCount.end()) - // ExprTypeToMissingOriginCount[ExprStr] = 1; - // else - // CountIt->second++; - // If the expression itself has no specific origin, and it's a reference // to a declaration, its origin is that of the declaration it refers to. // For pointer types, where we don't pre-emptively create an origin for the >From 0ca0f5876e2a9a6184e729d0de5b7bc4b2bbf311 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Thu, 27 Nov 2025 06:14:25 +0000 Subject: [PATCH 6/7] Made MissingOriginCollector internal to Origins.cpp --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 5 +- .../Analyses/LifetimeSafety/Origins.h | 20 +------ .../LifetimeSafety/LifetimeSafety.cpp | 13 ++--- clang/lib/Analysis/LifetimeSafety/Origins.cpp | 55 +++++++++++-------- clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 - 5 files changed, 43 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index cb11bbe863c0a..06f1a093233fa 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -39,8 +39,10 @@ enum class Confidence : uint8_t { }; /// A structure to hold the statistics related to LifetimeAnalysis. -/// Curently it holds only the missing origin details. +/// Currently it holds only the missing origin details. struct LifetimeSafetyStats { + /// A map from `ExpressionClassName<QualType>` to their missing origin + /// counts. llvm::StringMap<unsigned> MissingOriginCount; }; @@ -106,7 +108,6 @@ class LifetimeSafetyAnalysis { std::unique_ptr<LoanPropagationAnalysis> LoanPropagation; }; } // namespace internal - } // namespace clang::lifetimes #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h index baf9bb9be8439..05a19def04d96 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h @@ -87,9 +87,7 @@ class OriginManager { void dump(OriginID OID, llvm::raw_ostream &OS) const; - const llvm::DenseMap<const clang::Expr *, OriginID> & - getExprToOriginId() const; - + /// Collects statistics about expressions that lack associated origins. void collectMissingOrigins(Stmt *FunctionBody, LifetimeSafetyStats &LSStats); private: @@ -102,22 +100,6 @@ class OriginManager { llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID; llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID; }; - -/// An 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 OriginManager &om, - llvm::StringMap<unsigned> &MissingOriginCount) - : OM(om), MissingOriginCount(MissingOriginCount) {} - bool VisitExpr(Expr *E); - -private: - const OriginManager &OM; - llvm::StringMap<unsigned> &MissingOriginCount; -}; - } // namespace clang::lifetimes::internal #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_ORIGINS_H diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index cc0acbd42df39..e1f016b9d58a4 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -84,22 +84,21 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM, void printStats(const LifetimeSafetyStats &Stats) { llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " "(expression_type : count) :\n\n"; - unsigned totalMissingOrigins = 0; + unsigned TotalMissingOrigins = 0; for (const auto &[expr, count] : Stats.MissingOriginCount) { llvm::errs() << expr << " : " << count << '\n'; - totalMissingOrigins += count; + TotalMissingOrigins += count; } - llvm::errs() << "Total missing origins: " << totalMissingOrigins << "\n"; + llvm::errs() << "Total missing origins: " << TotalMissingOrigins << "\n"; llvm::errs() << "\n****************************************\n"; } void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, LifetimeSafetyStats &Stats, bool CollectStats) { - std::unique_ptr<internal::LifetimeSafetyAnalysis> Analysis = - std::make_unique<internal::LifetimeSafetyAnalysis>(AC, Reporter); - Analysis->run(); + internal::LifetimeSafetyAnalysis Analysis(AC, Reporter); + Analysis.run(); if (CollectStats) - collectLifetimeStats(AC, Analysis->getFactManager().getOriginMgr(), Stats); + collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats); } } // namespace clang::lifetimes diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index 03efc27e9d959..ece6535880fe9 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -34,6 +34,37 @@ static bool hasOrigin(const Expr *E) { return E->isGLValue() || isPointerType(E->getType()); } +namespace { +/// An 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 *, OriginID> &ExprToOriginId, + llvm::StringMap<unsigned> &MissingOriginCount) + : ExprToOriginId(ExprToOriginId), MissingOriginCount(MissingOriginCount) { + } + bool VisitExpr(Expr *E) { + if (!hasOrigin(E)) + return true; + // Check if we have an origin for this expression. + auto It = this->ExprToOriginId.find(E); + if (It == this->ExprToOriginId.end()) { + // No origin found: count this as missing origin. + std::string ExprStr = std::string(E->getStmtClassName()) + + " (Type: " + E->getType().getAsString() + ")"; + MissingOriginCount[ExprStr]++; + } + return true; + } + +private: + const llvm::DenseMap<const clang::Expr *, OriginID> &ExprToOriginId; + llvm::StringMap<unsigned> &MissingOriginCount; +}; +} // namespace + void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const { OS << OID << " ("; Origin O = getOrigin(OID); @@ -63,7 +94,6 @@ OriginID OriginManager::get(const Expr &E) { auto It = ExprToOriginID.find(&E); if (It != ExprToOriginID.end()) return It->second; - // If the expression itself has no specific origin, and it's a reference // to a declaration, its origin is that of the declaration it refers to. // For pointer types, where we don't pre-emptively create an origin for the @@ -113,33 +143,14 @@ OriginID OriginManager::getOrCreate(const ValueDecl &D) { return NewID; } -const llvm::DenseMap<const clang::Expr *, OriginID> & -OriginManager::getExprToOriginId() const { - return ExprToOriginID; -} - void OriginManager::collectMissingOrigins(Stmt *FunctionBody, LifetimeSafetyStats &LSStats) { if (!FunctionBody) return; - MissingOriginCollector Collector(*this, LSStats.MissingOriginCount); + MissingOriginCollector Collector(this->ExprToOriginID, + LSStats.MissingOriginCount); Collector.TraverseStmt(const_cast<Stmt *>(FunctionBody)); } -bool MissingOriginCollector::VisitExpr(Expr *E) { - if (!hasOrigin(E)) - return true; - // Check if we have an origin for this expression - const auto &ExprToOriginId = OM.getExprToOriginId(); - auto It = ExprToOriginId.find(E); - if (It == ExprToOriginId.end()) { - // No origin found - count this as missing - std::string ExprStr = std::string(E->getStmtClassName()) + "<" + - E->getType().getAsString() + ">"; - MissingOriginCount[ExprStr]++; - } - return true; -} - } // namespace clang::lifetimes::internal diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 9188b87e7faa9..4e0b75ef2d8ed 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -29,9 +29,7 @@ #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/CalledOnceCheck.h" #include "clang/Analysis/Analyses/Consumed.h" -#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" -#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/UninitializedValues.h" @@ -49,7 +47,6 @@ #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" >From a30fa2e3003d2cb7120e8bd298c6acfb1ad0ece8 Mon Sep 17 00:00:00 2001 From: Debadri Basak <[email protected]> Date: Thu, 27 Nov 2025 09:20:59 +0000 Subject: [PATCH 7/7] Introducing a dedicated file for LifetimeSafetyStats and changing the report format. instead of using ExprClassName<QualType> it will be shown in the following way: ``` *** LifetimeSafety Missing Origin Stats (expression_type : count) : UnaryOperator (Type: const value_type) : 1 BinaryOperator (Type: char *) : 3 CXXOperatorCallExpr (Type: const value_type) : 2 CXXMemberCallExpr (Type: basic_string_view<char>) : 1 DeclRefExpr (Type: char *) : 9 CXXMemberCallExpr (Type: const_iterator) : 1 CXXOperatorCallExpr (Type: class std::basic_string<char>) : 1 DeclRefExpr (Type: std::string_view) : 27 CXXOperatorCallExpr (Type: basic_string<char>) : 3 Total missing origins: 48 ``` --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 13 +------- .../Analyses/LifetimeSafety/LifetimeStats.h | 33 +++++++++++++++++++ .../Analyses/LifetimeSafety/Origins.h | 8 +---- .../clang/Sema/AnalysisBasedWarnings.h | 4 +-- .../Analysis/LifetimeSafety/CMakeLists.txt | 1 + .../LifetimeSafety/LifetimeSafety.cpp | 15 +-------- .../Analysis/LifetimeSafety/LifetimeStats.cpp | 30 +++++++++++++++++ clang/lib/Analysis/LifetimeSafety/Origins.cpp | 24 ++++---------- clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- 9 files changed, 75 insertions(+), 55 deletions(-) create mode 100644 clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h create mode 100644 clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 06f1a093233fa..7c0744ec007c5 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -21,11 +21,11 @@ #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" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/raw_ostream.h" #include <string> @@ -38,14 +38,6 @@ enum class Confidence : uint8_t { Definite // Reported as a definite error (-Wlifetime-safety-permissive) }; -/// A structure to hold the statistics related to LifetimeAnalysis. -/// Currently it holds only the missing origin details. -struct LifetimeSafetyStats { - /// A map from `ExpressionClassName<QualType>` to their missing origin - /// counts. - llvm::StringMap<unsigned> MissingOriginCount; -}; - class LifetimeSafetyReporter { public: LifetimeSafetyReporter() = default; @@ -61,9 +53,6 @@ class LifetimeSafetyReporter { Confidence Confidence) {} }; -// utility function to print missing origin stats. -void printStats(const LifetimeSafetyStats &Stats); - /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, 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..1f8fcc3fa68e0 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h @@ -0,0 +1,33 @@ +//===- LifetimeStats.h - Miscellaneous statistics related to lifetime safety +//analysis ---*- 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 +// staticstics related to Lifetimesafety analysis. +// +//===----------------------------------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H + +#include "llvm/ADT/StringMap.h" + +namespace clang::lifetimes { +/// A structure to hold the statistics related to LifetimeAnalysis. +/// Currently it holds only the missing origin details. +struct LifetimeSafetyStats { + /// A map from `ExpressionClassName<QualType>` to their missing origin + /// counts. + llvm::StringMap<unsigned> MissingOriginCount; +}; + +// utility function to print missing origin stats. +void printStats(const LifetimeSafetyStats &Stats); +} // namespace clang::lifetimes + +#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H \ No newline at end of file diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h index 05a19def04d96..8e3a4ac3554f1 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h @@ -16,17 +16,11 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeBase.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h" #include "clang/Analysis/Analyses/LifetimeSafety/Utils.h" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/raw_ostream.h" -namespace clang::lifetimes { - -struct LifetimeSafetyStats; -} // namespace clang::lifetimes - namespace clang::lifetimes::internal { using OriginID = utils::ID<struct OriginTag>; diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h index d17486a66b297..126e32a857ced 100644 --- a/clang/include/clang/Sema/AnalysisBasedWarnings.h +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -16,11 +16,9 @@ #include "clang/AST/Decl.h" #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Sema/ScopeInfo.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringMap.h" #include <memory> namespace clang { 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 e1f016b9d58a4..68f8492e70aea 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -18,17 +18,16 @@ #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" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" -#include "llvm/Support/raw_ostream.h" #include <memory> namespace clang::lifetimes { @@ -81,18 +80,6 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM, } } // namespace internal -void printStats(const LifetimeSafetyStats &Stats) { - llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " - "(expression_type : count) :\n\n"; - unsigned TotalMissingOrigins = 0; - for (const auto &[expr, count] : Stats.MissingOriginCount) { - llvm::errs() << expr << " : " << count << '\n'; - TotalMissingOrigins += count; - } - llvm::errs() << "Total missing origins: " << TotalMissingOrigins << "\n"; - llvm::errs() << "\n****************************************\n"; -} - void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter, LifetimeSafetyStats &Stats, bool CollectStats) { diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp new file mode 100644 index 0000000000000..dae2294e58564 --- /dev/null +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp @@ -0,0 +1,30 @@ +//===- LifetimeStats.cpp - Miscellaneous statistics related to C++ Lifetime +//Safety analysis -*--------- 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 "llvm/Support/raw_ostream.h" + +namespace clang::lifetimes { +void printStats(const LifetimeSafetyStats &Stats) { + llvm::errs() << "\n*** LifetimeSafety Missing Origin Stats " + "(expression_type : count) :\n\n"; + unsigned TotalMissingOrigins = 0; + for (const auto &[expr, count] : Stats.MissingOriginCount) { + llvm::errs() << expr << " : " << count << '\n'; + TotalMissingOrigins += count; + } + llvm::errs() << "Total missing origins: " << TotalMissingOrigins << "\n"; + llvm::errs() << "\n****************************************\n"; +} +} // namespace clang::lifetimes \ No newline at end of file diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index ece6535880fe9..b9759ea40b623 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -8,33 +8,21 @@ #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" #include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeBase.h" -#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h" #include "llvm/ADT/StringMap.h" namespace clang::lifetimes::internal { - -static bool isGslPointerType(QualType QT) { - if (const auto *RD = QT->getAsCXXRecordDecl()) { - // We need to check the template definition for specializations. - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) - return CTSD->getSpecializedTemplate() - ->getTemplatedDecl() - ->hasAttr<PointerAttr>(); - return RD->hasAttr<PointerAttr>(); - } - return false; -} - -static bool isPointerType(QualType QT) { +namespace { +bool isPointerType(QualType QT) { return QT->isPointerOrReferenceType() || isGslPointerType(QT); } // Check if a type has an origin. -static bool hasOrigin(const Expr *E) { +bool hasOrigin(const Expr *E) { return E->isGLValue() || isPointerType(E->getType()); } - -namespace { /// An utility class to traverse the function body in the analysis /// context and collect the count of expressions with missing origins. class MissingOriginCollector diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 4e0b75ef2d8ed..27e67c69eccc6 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -3175,8 +3175,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } void clang::sema::AnalysisBasedWarnings::PrintStats() const { - llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; + unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; unsigned AvgCFGBlocksPerFunction = !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
