88#include " clang/Analysis/Analyses/LifetimeSafety.h"
99#include " clang/AST/Decl.h"
1010#include " clang/AST/Expr.h"
11+ #include " clang/AST/RecursiveASTVisitor.h"
1112#include " clang/AST/StmtVisitor.h"
1213#include " clang/AST/Type.h"
1314#include " clang/Analysis/Analyses/PostOrderCFGView.h"
@@ -387,25 +388,16 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
387388 using Base = ConstStmtVisitor<FactGenerator>;
388389
389390public:
390- FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
391- : FactMgr(FactMgr), AC(AC) {}
391+ FactGenerator (FactManager &FactMgr) : FactMgr(FactMgr) {}
392392
393- void run () {
394- llvm::TimeTraceScope TimeProfile (" FactGenerator" );
395- // Iterate through the CFG blocks in reverse post-order to ensure that
396- // initializations and destructions are processed in the correct sequence.
397- for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
398- CurrentBlockFacts.clear ();
399- for (unsigned I = 0 ; I < Block->size (); ++I) {
400- const CFGElement &Element = Block->Elements [I];
401- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
402- Visit (CS->getStmt ());
403- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
404- Element.getAs <CFGAutomaticObjDtor>())
405- handleDestructor (*DtorOpt);
406- }
407- FactMgr.addBlockFacts (Block, CurrentBlockFacts);
408- }
393+ void startBlock (const CFGBlock *Block) {
394+ CurrentBlock = Block;
395+ CurrentBlockFacts.clear ();
396+ }
397+
398+ void endBlock () {
399+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
400+ startBlock (nullptr );
409401 }
410402
411403 void VisitDeclStmt (const DeclStmt *DS) {
@@ -425,7 +417,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
425417 void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
426418 if (!hasOrigin (ICE->getType ()))
427419 return ;
428- Visit (ICE->getSubExpr ());
429420 // An ImplicitCastExpr node itself gets an origin, which flows from the
430421 // origin of its sub-expression (after stripping its own parens/casts).
431422 // TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -493,18 +484,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
493484 Base::VisitCXXFunctionalCastExpr (FCE);
494485 }
495486
496- private:
497- // Check if a type has an origin.
498- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
499-
500- template <typename Destination, typename Source>
501- void addAssignOriginFact (const Destination &D, const Source &S) {
502- OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
503- OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
504- CurrentBlockFacts.push_back (
505- FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
506- }
507-
508487 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
509488 // / TODO: Also handle trivial destructors (e.g., for `int`
510489 // / variables) which will never have a CFGAutomaticObjDtor node.
@@ -527,6 +506,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
527506 }
528507 }
529508
509+ private:
510+ // Check if a type has an origin.
511+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
512+
513+ template <typename Destination, typename Source>
514+ void addAssignOriginFact (const Destination &D, const Source &S) {
515+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
516+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
517+ CurrentBlockFacts.push_back (
518+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
519+ }
520+
530521 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
531522 // / If so, creates a `TestPointFact` and returns true.
532523 bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -549,10 +540,59 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
549540 }
550541
551542 FactManager &FactMgr;
552- AnalysisDeclContext &AC ;
543+ const CFGBlock *CurrentBlock = nullptr ;
553544 llvm::SmallVector<Fact *> CurrentBlockFacts;
554545};
555546
547+ class FactGeneratorDriver : public RecursiveASTVisitor <FactGeneratorDriver> {
548+ public:
549+ FactGeneratorDriver (FactGenerator &FG, AnalysisDeclContext &AC)
550+ : FG(FG), AC(AC) {}
551+ bool shouldTraversePostOrder () const { return true ; }
552+ void run () {
553+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
554+ // Iterate through the CFG blocks in reverse post-order to ensure that
555+ // initializations and destructions are processed in the correct sequence.
556+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
557+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
558+ for (const CFGElement &Element : *Block) {
559+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
560+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
561+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
562+ Element.getAs <CFGAutomaticObjDtor>())
563+ FG.handleDestructor (*DtorOpt);
564+ }
565+ }
566+ }
567+
568+ bool TraverseStmt (Stmt *S) {
569+ // Avoid re-visiting nodes to not create duplicate facts.
570+ if (!S || !VisitedStmts.insert (S).second )
571+ return true ;
572+ return RecursiveASTVisitor::TraverseStmt (S);
573+ }
574+
575+ bool VisitStmt (Stmt *S) {
576+ FG.Visit (S);
577+ return true ; // Continue traversing to children.
578+ }
579+
580+ private:
581+ struct FactGeneratorBlockRAII {
582+ FactGeneratorBlockRAII (FactGenerator &FG, const CFGBlock *Block) : FG(FG) {
583+ FG.startBlock (Block);
584+ }
585+ ~FactGeneratorBlockRAII () { FG.endBlock (); }
586+
587+ private:
588+ FactGenerator FG;
589+ };
590+
591+ FactGenerator &FG;
592+ AnalysisDeclContext &AC;
593+ llvm::DenseSet<const Stmt *> VisitedStmts;
594+ };
595+
556596// ========================================================================= //
557597// Generic Dataflow Analysis
558598// ========================================================================= //
@@ -1096,8 +1136,9 @@ void LifetimeSafetyAnalysis::run() {
10961136 DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
10971137 /* ShowColors=*/ true ));
10981138
1099- FactGenerator FactGen (*FactMgr, AC);
1100- FactGen.run ();
1139+ FactGenerator Generator (*FactMgr);
1140+ FactGeneratorDriver Driver (Generator, AC);
1141+ Driver.run ();
11011142 DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
11021143
11031144 // / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments