8
8
#include " clang/Analysis/Analyses/LifetimeSafety.h"
9
9
#include " clang/AST/Decl.h"
10
10
#include " clang/AST/Expr.h"
11
+ #include " clang/AST/RecursiveASTVisitor.h"
11
12
#include " clang/AST/StmtVisitor.h"
12
13
#include " clang/AST/Type.h"
13
14
#include " clang/Analysis/Analyses/PostOrderCFGView.h"
@@ -403,29 +404,15 @@ class FactManager {
403
404
llvm::BumpPtrAllocator FactAllocator;
404
405
};
405
406
406
- class FactGenerator : public ConstStmtVisitor <FactGenerator > {
407
- using Base = ConstStmtVisitor<FactGenerator >;
407
+ class FactGeneratorVisitor : public ConstStmtVisitor <FactGeneratorVisitor > {
408
+ using Base = ConstStmtVisitor<FactGeneratorVisitor >;
408
409
409
410
public:
410
- FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
411
- : FactMgr(FactMgr), AC(AC) {}
411
+ FactGeneratorVisitor (FactManager &FactMgr) : FactMgr(FactMgr) {}
412
412
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 ();
429
416
}
430
417
431
418
void VisitDeclStmt (const DeclStmt *DS) {
@@ -445,7 +432,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
445
432
void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
446
433
if (!hasOrigin (ICE->getType ()))
447
434
return ;
448
- Visit (ICE->getSubExpr ());
449
435
// An ImplicitCastExpr node itself gets an origin, which flows from the
450
436
// origin of its sub-expression (after stripping its own parens/casts).
451
437
// TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -513,18 +499,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
513
499
Base::VisitCXXFunctionalCastExpr (FCE);
514
500
}
515
501
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
-
528
502
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
529
503
// / TODO: Also handle trivial destructors (e.g., for `int`
530
504
// / variables) which will never have a CFGAutomaticObjDtor node.
@@ -547,6 +521,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
547
521
}
548
522
}
549
523
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
+
550
536
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
551
537
// / If so, creates a `TestPointFact` and returns true.
552
538
bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -569,10 +555,60 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
569
555
}
570
556
571
557
FactManager &FactMgr;
572
- AnalysisDeclContext &AC;
573
558
llvm::SmallVector<Fact *> CurrentBlockFacts;
574
559
};
575
560
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
+
576
612
// ========================================================================= //
577
613
// Generic Dataflow Analysis
578
614
// ========================================================================= //
@@ -1116,8 +1152,8 @@ void LifetimeSafetyAnalysis::run() {
1116
1152
DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
1117
1153
/* ShowColors=*/ true ));
1118
1154
1119
- FactGenerator FactGen (*FactMgr, AC);
1120
- FactGen .run ();
1155
+ FactGenerator FG (*FactMgr, AC);
1156
+ FG .run ();
1121
1157
DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
1122
1158
1123
1159
// / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments