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"
@@ -387,25 +388,16 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
387
388
using Base = ConstStmtVisitor<FactGenerator>;
388
389
389
390
public:
390
- FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
391
- : FactMgr(FactMgr), AC(AC) {}
391
+ FactGenerator (FactManager &FactMgr) : FactMgr(FactMgr) {}
392
392
393
- void run () {
394
- llvm::TimeTraceScope TimeProfile (" FactGenerator" );
395
- // Iterate through the CFG blocks in reverse post-order to ensure that
396
- // initializations and destructions are processed in the correct sequence.
397
- for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
398
- CurrentBlockFacts.clear ();
399
- for (unsigned I = 0 ; I < Block->size (); ++I) {
400
- const CFGElement &Element = Block->Elements [I];
401
- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
402
- Visit (CS->getStmt ());
403
- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
404
- Element.getAs <CFGAutomaticObjDtor>())
405
- handleDestructor (*DtorOpt);
406
- }
407
- FactMgr.addBlockFacts (Block, CurrentBlockFacts);
408
- }
393
+ void startBlock (const CFGBlock *Block) {
394
+ CurrentBlock = Block;
395
+ CurrentBlockFacts.clear ();
396
+ }
397
+
398
+ void endBlock () {
399
+ FactMgr.addBlockFacts (CurrentBlock, CurrentBlockFacts);
400
+ startBlock (nullptr );
409
401
}
410
402
411
403
void VisitDeclStmt (const DeclStmt *DS) {
@@ -425,7 +417,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
425
417
void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
426
418
if (!hasOrigin (ICE->getType ()))
427
419
return ;
428
- Visit (ICE->getSubExpr ());
429
420
// An ImplicitCastExpr node itself gets an origin, which flows from the
430
421
// origin of its sub-expression (after stripping its own parens/casts).
431
422
// TODO: Consider if this is actually useful in practice. Alternatively, we
@@ -493,18 +484,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
493
484
Base::VisitCXXFunctionalCastExpr (FCE);
494
485
}
495
486
496
- private:
497
- // Check if a type has an origin.
498
- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
499
-
500
- template <typename Destination, typename Source>
501
- void addAssignOriginFact (const Destination &D, const Source &S) {
502
- OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
503
- OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
504
- CurrentBlockFacts.push_back (
505
- FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
506
- }
507
-
508
487
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
509
488
// / TODO: Also handle trivial destructors (e.g., for `int`
510
489
// / variables) which will never have a CFGAutomaticObjDtor node.
@@ -526,6 +505,17 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
526
505
L.ID , DtorOpt.getTriggerStmt ()->getEndLoc ()));
527
506
}
528
507
}
508
+ private:
509
+ // Check if a type has an origin.
510
+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
511
+
512
+ template <typename Destination, typename Source>
513
+ void addAssignOriginFact (const Destination &D, const Source &S) {
514
+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
515
+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
516
+ CurrentBlockFacts.push_back (
517
+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
518
+ }
529
519
530
520
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
531
521
// / If so, creates a `TestPointFact` and returns true.
@@ -549,10 +539,59 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
549
539
}
550
540
551
541
FactManager &FactMgr;
552
- AnalysisDeclContext &AC ;
542
+ const CFGBlock *CurrentBlock = nullptr ;
553
543
llvm::SmallVector<Fact *> CurrentBlockFacts;
554
544
};
555
545
546
+ class FactGeneratorDriver : public RecursiveASTVisitor <FactGeneratorDriver> {
547
+ public:
548
+ FactGeneratorDriver (FactGenerator &FG, AnalysisDeclContext &AC)
549
+ : FG(FG), AC(AC) {}
550
+ bool shouldTraversePostOrder () const { return true ; }
551
+ void run () {
552
+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
553
+ // Iterate through the CFG blocks in reverse post-order to ensure that
554
+ // initializations and destructions are processed in the correct sequence.
555
+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
556
+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
557
+ for (const CFGElement &Element : *Block) {
558
+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
559
+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
560
+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
561
+ Element.getAs <CFGAutomaticObjDtor>())
562
+ FG.handleDestructor (*DtorOpt);
563
+ }
564
+ }
565
+ }
566
+
567
+ bool TraverseStmt (Stmt *S) {
568
+ // Avoid re-visiting nodes to not create duplicate facts.
569
+ if (!S || !VisitedStmts.insert (S).second )
570
+ return true ;
571
+ return RecursiveASTVisitor::TraverseStmt (S);
572
+ }
573
+
574
+ bool VisitStmt (Stmt *S) {
575
+ FG.Visit (S);
576
+ return true ; // Continue traversing to children.
577
+ }
578
+
579
+ private:
580
+ struct FactGeneratorBlockRAII {
581
+ FactGeneratorBlockRAII (FactGenerator &FG, const CFGBlock *Block) : FG(FG) {
582
+ FG.startBlock (Block);
583
+ }
584
+ ~FactGeneratorBlockRAII () { FG.endBlock (); }
585
+
586
+ private:
587
+ FactGenerator FG;
588
+ };
589
+
590
+ FactGenerator &FG;
591
+ AnalysisDeclContext &AC;
592
+ llvm::DenseSet<const Stmt *> VisitedStmts;
593
+ };
594
+
556
595
// ========================================================================= //
557
596
// Generic Dataflow Analysis
558
597
// ========================================================================= //
@@ -1096,8 +1135,9 @@ void LifetimeSafetyAnalysis::run() {
1096
1135
DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
1097
1136
/* ShowColors=*/ true ));
1098
1137
1099
- FactGenerator FactGen (*FactMgr, AC);
1100
- FactGen.run ();
1138
+ FactGenerator Generator (*FactMgr);
1139
+ FactGeneratorDriver Driver (Generator, AC);
1140
+ Driver.run ();
1101
1141
DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
1102
1142
1103
1143
// / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments