Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@
#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/Support/raw_ostream.h"
#include <string>

namespace clang::lifetimes {

Expand Down Expand Up @@ -51,9 +55,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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===- 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 "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 `QualType` to their missing origin counts.
llvm::StringMap<unsigned> ExprStmtClassToMissingOriginCount;
/// A map from `StmtClassName` to their missing origin counts.
llvm::StringMap<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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

#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 {

Expand Down Expand Up @@ -78,6 +81,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++; }

Expand Down
8 changes: 6 additions & 2 deletions clang/include/clang/Sema/AnalysisBasedWarnings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_clang_library(clangAnalysisLifetimeSafety
LifetimeAnnotations.cpp
LifetimeSafety.cpp
LiveOrigins.cpp
LifetimeStats.cpp
Loans.cpp
LoanPropagation.cpp
Origins.cpp
Expand Down
15 changes: 14 additions & 1 deletion clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -68,11 +70,22 @@ 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 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
34 changes: 34 additions & 0 deletions clang/lib/Analysis/LifetimeSafety/LifetimeStats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===- 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 "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 &[type, count] : Stats.ExprTypeToMissingOriginCount) {
llvm::errs() << type << " : " << count << '\n';
TotalMissingOrigins += count;
}
llvm::errs() << "\n\n*** LifetimeSafety Missing Origin per StmtClassName: "
"(StmtClassName : count) :\n\n";
for (const auto &[stmt, count] : Stats.ExprStmtClassToMissingOriginCount) {
llvm::errs() << stmt << " : " << count << '\n';
}
llvm::errs() << "\nTotal missing origins: " << TotalMissingOrigins << "\n";
llvm::errs() << "\n****************************************\n";
}
} // namespace clang::lifetimes
55 changes: 55 additions & 0 deletions clang/lib/Analysis/LifetimeSafety/Origins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,52 @@
//===----------------------------------------------------------------------===//

#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/LifetimeAnnotations.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
#include "llvm/ADT/StringMap.h"

namespace clang::lifetimes::internal {
namespace {
bool isPointerType(QualType QT) {
return QT->isPointerOrReferenceType() || isGslPointerType(QT);
}
// Check if a type has an origin.
bool hasOrigin(const Expr *E) {
return E->isGLValue() || isPointerType(E->getType());
}
/// 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 *, OriginID> &ExprToOriginId,
llvm::StringMap<unsigned> &ExprStmtClassToMissingOriginCount,
llvm::StringMap<unsigned> &ExprTypeToMissingOriginCount)
: ExprToOriginId(ExprToOriginId),
ExprStmtClassToMissingOriginCount(ExprStmtClassToMissingOriginCount),
ExprTypeToMissingOriginCount(ExprTypeToMissingOriginCount) {}
bool VisitExpr(Expr *E) {
if (!hasOrigin(E))
return true;
// Check if we have an origin for this expression.
if (!ExprToOriginId.contains(E)) {
// No origin found: count this as missing origin.
ExprTypeToMissingOriginCount[std::string(E->getType().getAsString())]++;
ExprStmtClassToMissingOriginCount[std::string(E->getStmtClassName())]++;
}
return true;
}

private:
const llvm::DenseMap<const clang::Expr *, OriginID> &ExprToOriginId;
llvm::StringMap<unsigned> &ExprStmtClassToMissingOriginCount;
llvm::StringMap<unsigned> &ExprTypeToMissingOriginCount;
};
} // namespace

void OriginManager::dump(OriginID OID, llvm::raw_ostream &OS) const {
OS << OID << " (";
Expand Down Expand Up @@ -88,4 +132,15 @@ OriginID OriginManager::getOrCreate(const ValueDecl &D) {
return NewID;
}

void OriginManager::collectMissingOrigins(Stmt *FunctionBody,
LifetimeSafetyStats &LSStats) {
if (!FunctionBody)
return;

MissingOriginCollector Collector(this->ExprToOriginID,
LSStats.ExprStmtClassToMissingOriginCount,
LSStats.ExprTypeToMissingOriginCount);
Collector.TraverseStmt(const_cast<Stmt *>(FunctionBody));
}

} // namespace clang::lifetimes::internal
4 changes: 3 additions & 1 deletion clang/lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3107,7 +3107,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.
Expand Down Expand Up @@ -3203,4 +3204,5 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
<< " average block visits per function.\n"
<< " " << MaxUninitAnalysisBlockVisitsPerFunction
<< " max block visits per function.\n";
clang::lifetimes::printStats(LSStats);
}