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,20 @@ 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 (const CFGBlock *Block) {
414+ CurrentBlock = Block;
415+ CurrentBlockFacts.clear ();
416+ }
417+
418+ void endBlock () {
419+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
420+ startBlock (nullptr );
429421 }
430422
431423 void VisitDeclStmt (const DeclStmt *DS) {
@@ -445,7 +437,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
445437 void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
446438 if (!hasOrigin (ICE->getType ()))
447439 return ;
448- Visit (ICE->getSubExpr ());
449440 // An ImplicitCastExpr node itself gets an origin, which flows from the
450441 // origin of its sub-expression (after stripping its own parens/casts).
451442 // TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -513,18 +504,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
513504 Base::VisitCXXFunctionalCastExpr (FCE);
514505 }
515506
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-
528507 void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
529508 // / TODO: Also handle trivial destructors (e.g., for `int`
530509 // / variables) which will never have a CFGAutomaticObjDtor node.
@@ -547,6 +526,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
547526 }
548527 }
549528
529+ private:
530+ // Check if a type has an origin.
531+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
532+
533+ template <typename Destination, typename Source>
534+ void addAssignOriginFact (const Destination &D, const Source &S) {
535+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
536+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
537+ CurrentBlockFacts.push_back (
538+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
539+ }
540+
550541 // / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
551542 // / If so, creates a `TestPointFact` and returns true.
552543 bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -569,10 +560,62 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
569560 }
570561
571562 FactManager &FactMgr;
572- AnalysisDeclContext &AC ;
563+ const CFGBlock *CurrentBlock = nullptr ;
573564 llvm::SmallVector<Fact *> CurrentBlockFacts;
574565};
575566
567+ class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
568+ public:
569+ FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
570+ : FG(FactMgr), AC(AC) {}
571+
572+ bool shouldTraversePostOrder () const { return true ; }
573+
574+ void run () {
575+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
576+ // Iterate through the CFG blocks in reverse post-order to ensure that
577+ // initializations and destructions are processed in the correct sequence.
578+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
579+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
580+ for (const CFGElement &Element : *Block) {
581+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
582+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
583+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
584+ Element.getAs <CFGAutomaticObjDtor>())
585+ FG.handleDestructor (*DtorOpt);
586+ }
587+ }
588+ }
589+
590+ bool TraverseStmt (Stmt *S) {
591+ // Avoid re-visiting nodes to not create duplicate facts.
592+ if (!S || !VisitedStmts.insert (S).second )
593+ return true ;
594+ return RecursiveASTVisitor::TraverseStmt (S);
595+ }
596+
597+ bool VisitStmt (Stmt *S) {
598+ FG.Visit (S);
599+ return true ; // Continue traversing to children.
600+ }
601+
602+ private:
603+ struct FactGeneratorBlockRAII {
604+ FactGeneratorBlockRAII (FactGeneratorVisitor &FG, const CFGBlock *Block)
605+ : FG(FG) {
606+ FG.startBlock (Block);
607+ }
608+ ~FactGeneratorBlockRAII () { FG.endBlock (); }
609+
610+ private:
611+ FactGeneratorVisitor &FG;
612+ };
613+
614+ FactGeneratorVisitor FG;
615+ AnalysisDeclContext &AC;
616+ llvm::DenseSet<const Stmt *> VisitedStmts;
617+ };
618+
576619// ========================================================================= //
577620// Generic Dataflow Analysis
578621// ========================================================================= //
@@ -1116,8 +1159,8 @@ void LifetimeSafetyAnalysis::run() {
11161159 DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
11171160 /* ShowColors=*/ true ));
11181161
1119- FactGenerator FactGen (*FactMgr, AC);
1120- FactGen .run ();
1162+ FactGenerator FG (*FactMgr, AC);
1163+ FG .run ();
11211164 DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
11221165
11231166 // / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments