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"
@@ -403,29 +404,17 @@ class FactManager {
403404 llvm::BumpPtrAllocator FactAllocator;
404405};
405406
406- class FactGenerator : public ConstStmtVisitor <FactGenerator > {
407- using Base = ConstStmtVisitor<FactGenerator >;
407+ class FactGeneratorVisitor : public ConstStmtVisitor <FactGeneratorVisitor > {
408+ using Base = ConstStmtVisitor<FactGeneratorVisitor >;
408409
409410public:
410- FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
411- : FactMgr(FactMgr), AC(AC) {}
411+ FactGeneratorVisitor (FactManager &FactMgr) : FactMgr(FactMgr) {}
412412
413- void run () {
414- llvm::TimeTraceScope TimeProfile (" FactGenerator" );
415- // Iterate through the CFG blocks in reverse post-order to ensure that
416- // initializations and destructions are processed in the correct sequence.
417- for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
418- CurrentBlockFacts.clear ();
419- for (unsigned I = 0 ; I < Block->size (); ++I) {
420- const CFGElement &Element = Block->Elements [I];
421- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
422- Visit (CS->getStmt ());
423- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
424- Element.getAs <CFGAutomaticObjDtor>())
425- handleDestructor (*DtorOpt);
426- }
427- FactMgr.addBlockFacts (Block, CurrentBlockFacts);
428- }
413+ void startBlock () { CurrentBlockFacts.clear (); }
414+
415+ void endBlock (const CFGBlock *CurrentBlock) {
416+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
417+ CurrentBlockFacts.clear ();
429418 }
430419
431420 void VisitDeclStmt (const DeclStmt *DS) {
@@ -445,7 +434,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
445434 void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
446435 if (!hasOrigin (ICE->getType ()))
447436 return ;
448- Visit (ICE->getSubExpr ());
449437 // An ImplicitCastExpr node itself gets an origin, which flows from the
450438 // origin of its sub-expression (after stripping its own parens/casts).
451439 // TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -513,18 +501,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
513501 Base::VisitCXXFunctionalCastExpr (FCE);
514502 }
515503
516- private:
517- // Check if a type has an origin.
518- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
519-
520- template <typename Destination, typename Source>
521- void addAssignOriginFact (const Destination &D, const Source &S) {
522- OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
523- OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
524- CurrentBlockFacts.push_back (
525- FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
526- }
527-
528504 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
529505 // / TODO: Also handle trivial destructors (e.g., for `int`
530506 // / variables) which will never have a CFGAutomaticObjDtor node.
@@ -547,6 +523,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
547523 }
548524 }
549525
526+ private:
527+ // Check if a type has an origin.
528+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
529+
530+ template <typename Destination, typename Source>
531+ void addAssignOriginFact (const Destination &D, const Source &S) {
532+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
533+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
534+ CurrentBlockFacts.push_back (
535+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
536+ }
537+
550538 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
551539 // / If so, creates a `TestPointFact` and returns true.
552540 bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -569,10 +557,62 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
569557 }
570558
571559 FactManager &FactMgr;
572- AnalysisDeclContext &AC;
573560 llvm::SmallVector<Fact *> CurrentBlockFacts;
574561};
575562
563+ class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
564+ public:
565+ FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
566+ : FG(FactMgr), AC(AC) {}
567+
568+ bool shouldTraversePostOrder () const { return true ; }
569+
570+ void run () {
571+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
572+ // Iterate through the CFG blocks in reverse post-order to ensure that
573+ // initializations and destructions are processed in the correct sequence.
574+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
575+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
576+ for (const CFGElement &Element : *Block) {
577+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
578+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
579+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
580+ Element.getAs <CFGAutomaticObjDtor>())
581+ FG.handleDestructor (*DtorOpt);
582+ }
583+ }
584+ }
585+
586+ bool TraverseStmt (Stmt *S) {
587+ // Avoid re-visiting nodes to not create duplicate facts.
588+ if (!S || !VisitedStmts.insert (S).second )
589+ return true ;
590+ return RecursiveASTVisitor::TraverseStmt (S);
591+ }
592+
593+ bool VisitStmt (Stmt *S) {
594+ FG.Visit (S);
595+ return true ; // Continue traversing to children.
596+ }
597+
598+ private:
599+ struct FactGeneratorBlockRAII {
600+ FactGeneratorBlockRAII (FactGeneratorVisitor &FG, const CFGBlock *Block)
601+ : FG(FG), CurBlock(Block) {
602+ FG.startBlock ();
603+ }
604+ ~FactGeneratorBlockRAII () { FG.endBlock (CurBlock); }
605+
606+ private:
607+ FactGeneratorVisitor &FG;
608+ const CFGBlock *CurBlock;
609+ };
610+
611+ FactGeneratorVisitor FG;
612+ AnalysisDeclContext &AC;
613+ llvm::DenseSet<const Stmt *> VisitedStmts;
614+ };
615+
576616// ========================================================================= //
577617// Generic Dataflow Analysis
578618// ========================================================================= //
@@ -1116,8 +1156,8 @@ void LifetimeSafetyAnalysis::run() {
11161156 DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
11171157 /* ShowColors=*/ true ));
11181158
1119- FactGenerator FactGen (*FactMgr, AC);
1120- FactGen .run ();
1159+ FactGenerator FG (*FactMgr, AC);
1160+ FG .run ();
11211161 DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
11221162
11231163 // / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments