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,15 @@ 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 flushBlock (const CFGBlock *CurrentBlock) {
414+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
415+ CurrentBlockFacts.clear ();
429416 }
430417
431418 void VisitDeclStmt (const DeclStmt *DS) {
@@ -445,7 +432,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
445432 void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
446433 if (!hasOrigin (ICE->getType ()))
447434 return ;
448- Visit (ICE->getSubExpr ());
449435 // An ImplicitCastExpr node itself gets an origin, which flows from the
450436 // origin of its sub-expression (after stripping its own parens/casts).
451437 // TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -513,18 +499,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
513499 Base::VisitCXXFunctionalCastExpr (FCE);
514500 }
515501
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-
528502 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
529503 // / TODO: Also handle trivial destructors (e.g., for `int`
530504 // / variables) which will never have a CFGAutomaticObjDtor node.
@@ -547,6 +521,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
547521 }
548522 }
549523
524+ private:
525+ // Check if a type has an origin.
526+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
527+
528+ template <typename Destination, typename Source>
529+ void addAssignOriginFact (const Destination &D, const Source &S) {
530+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
531+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
532+ CurrentBlockFacts.push_back (
533+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
534+ }
535+
550536 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
551537 // / If so, creates a `TestPointFact` and returns true.
552538 bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -569,10 +555,60 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
569555 }
570556
571557 FactManager &FactMgr;
572- AnalysisDeclContext &AC;
573558 llvm::SmallVector<Fact *> CurrentBlockFacts;
574559};
575560
561+ class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
562+ public:
563+ FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
564+ : FG(FactMgr), AC(AC) {}
565+
566+ bool shouldTraversePostOrder () const { return true ; }
567+
568+ void run () {
569+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
570+ // Iterate through the CFG blocks in reverse post-order to ensure that
571+ // initializations and destructions are processed in the correct sequence.
572+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
573+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
574+ for (const CFGElement &Element : *Block) {
575+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
576+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
577+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
578+ Element.getAs <CFGAutomaticObjDtor>())
579+ FG.handleDestructor (*DtorOpt);
580+ }
581+ }
582+ }
583+
584+ bool TraverseStmt (Stmt *S) {
585+ // Avoid re-visiting nodes to not create duplicate facts.
586+ if (!S || !VisitedStmts.insert (S).second )
587+ return true ;
588+ return RecursiveASTVisitor::TraverseStmt (S);
589+ }
590+
591+ bool VisitStmt (Stmt *S) {
592+ FG.Visit (S);
593+ return true ; // Continue traversing to children.
594+ }
595+
596+ private:
597+ struct FactGeneratorBlockRAII {
598+ FactGeneratorBlockRAII (FactGeneratorVisitor &FG, const CFGBlock *Block)
599+ : FG(FG), CurBlock(Block) {}
600+ ~FactGeneratorBlockRAII () { FG.flushBlock (CurBlock); }
601+
602+ private:
603+ FactGeneratorVisitor &FG;
604+ const CFGBlock *CurBlock;
605+ };
606+
607+ FactGeneratorVisitor FG;
608+ AnalysisDeclContext &AC;
609+ llvm::DenseSet<const Stmt *> VisitedStmts;
610+ };
611+
576612// ========================================================================= //
577613// Generic Dataflow Analysis
578614// ========================================================================= //
@@ -1116,8 +1152,8 @@ void LifetimeSafetyAnalysis::run() {
11161152 DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
11171153 /* ShowColors=*/ true ));
11181154
1119- FactGenerator FactGen (*FactMgr, AC);
1120- FactGen .run ();
1155+ FactGenerator FG (*FactMgr, AC);
1156+ FG .run ();
11211157 DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
11221158
11231159 // / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments