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,17 @@ 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 startBlock () { CurrentBlockFacts.clear (); }
414
+
415
+ void endBlock (const CFGBlock *CurrentBlock) {
416
+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
417
+ CurrentBlockFacts.clear ();
429
418
}
430
419
431
420
void VisitDeclStmt (const DeclStmt *DS) {
@@ -445,7 +434,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
445
434
void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
446
435
if (!hasOrigin (ICE->getType ()))
447
436
return ;
448
- Visit (ICE->getSubExpr ());
449
437
// An ImplicitCastExpr node itself gets an origin, which flows from the
450
438
// origin of its sub-expression (after stripping its own parens/casts).
451
439
// TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -513,18 +501,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
513
501
Base::VisitCXXFunctionalCastExpr (FCE);
514
502
}
515
503
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
504
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
529
505
// / TODO: Also handle trivial destructors (e.g., for `int`
530
506
// / variables) which will never have a CFGAutomaticObjDtor node.
@@ -547,6 +523,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
547
523
}
548
524
}
549
525
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
+
550
538
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
551
539
// / If so, creates a `TestPointFact` and returns true.
552
540
bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -569,10 +557,62 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
569
557
}
570
558
571
559
FactManager &FactMgr;
572
- AnalysisDeclContext &AC;
573
560
llvm::SmallVector<Fact *> CurrentBlockFacts;
574
561
};
575
562
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
+
576
616
// ========================================================================= //
577
617
// Generic Dataflow Analysis
578
618
// ========================================================================= //
@@ -1116,8 +1156,8 @@ void LifetimeSafetyAnalysis::run() {
1116
1156
DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
1117
1157
/* ShowColors=*/ true ));
1118
1158
1119
- FactGenerator FactGen (*FactMgr, AC);
1120
- FactGen .run ();
1159
+ FactGenerator FG (*FactMgr, AC);
1160
+ FG .run ();
1121
1161
DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
1122
1162
1123
1163
// / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments