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"
@@ -383,29 +384,20 @@ class FactManager {
383
384
llvm::BumpPtrAllocator FactAllocator;
384
385
};
385
386
386
- class FactGenerator : public ConstStmtVisitor <FactGenerator > {
387
- using Base = ConstStmtVisitor<FactGenerator >;
387
+ class FactGeneratorVisitor : public ConstStmtVisitor <FactGeneratorVisitor > {
388
+ using Base = ConstStmtVisitor<FactGeneratorVisitor >;
388
389
389
390
public:
390
- FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
391
- : FactMgr(FactMgr), AC(AC) {}
391
+ FactGeneratorVisitor (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.
@@ -527,6 +506,18 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
527
506
}
528
507
}
529
508
509
+ private:
510
+ // Check if a type has an origin.
511
+ bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
512
+
513
+ template <typename Destination, typename Source>
514
+ void addAssignOriginFact (const Destination &D, const Source &S) {
515
+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
516
+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
517
+ CurrentBlockFacts.push_back (
518
+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
519
+ }
520
+
530
521
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
531
522
// / If so, creates a `TestPointFact` and returns true.
532
523
bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -549,10 +540,62 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
549
540
}
550
541
551
542
FactManager &FactMgr;
552
- AnalysisDeclContext &AC ;
543
+ const CFGBlock *CurrentBlock = nullptr ;
553
544
llvm::SmallVector<Fact *> CurrentBlockFacts;
554
545
};
555
546
547
+ class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
548
+ public:
549
+ FactGenerator (FactManager &FactMgr, AnalysisDeclContext &AC)
550
+ : FG(FactMgr), AC(AC) {}
551
+
552
+ bool shouldTraversePostOrder () const { return true ; }
553
+
554
+ void run () {
555
+ llvm::TimeTraceScope TimeProfile (" FactGenerator" );
556
+ // Iterate through the CFG blocks in reverse post-order to ensure that
557
+ // initializations and destructions are processed in the correct sequence.
558
+ for (const CFGBlock *Block : *AC.getAnalysis <PostOrderCFGView>()) {
559
+ FactGeneratorBlockRAII BlockGenerator (FG, Block);
560
+ for (const CFGElement &Element : *Block) {
561
+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
562
+ TraverseStmt (const_cast <Stmt *>(CS->getStmt ()));
563
+ else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
564
+ Element.getAs <CFGAutomaticObjDtor>())
565
+ FG.handleDestructor (*DtorOpt);
566
+ }
567
+ }
568
+ }
569
+
570
+ bool TraverseStmt (Stmt *S) {
571
+ // Avoid re-visiting nodes to not create duplicate facts.
572
+ if (!S || !VisitedStmts.insert (S).second )
573
+ return true ;
574
+ return RecursiveASTVisitor::TraverseStmt (S);
575
+ }
576
+
577
+ bool VisitStmt (Stmt *S) {
578
+ FG.Visit (S);
579
+ return true ; // Continue traversing to children.
580
+ }
581
+
582
+ private:
583
+ struct FactGeneratorBlockRAII {
584
+ FactGeneratorBlockRAII (FactGeneratorVisitor &FG, const CFGBlock *Block)
585
+ : FG(FG) {
586
+ FG.startBlock (Block);
587
+ }
588
+ ~FactGeneratorBlockRAII () { FG.endBlock (); }
589
+
590
+ private:
591
+ FactGeneratorVisitor &FG;
592
+ };
593
+
594
+ FactGeneratorVisitor FG;
595
+ AnalysisDeclContext &AC;
596
+ llvm::DenseSet<const Stmt *> VisitedStmts;
597
+ };
598
+
556
599
// ========================================================================= //
557
600
// Generic Dataflow Analysis
558
601
// ========================================================================= //
@@ -1096,8 +1139,8 @@ void LifetimeSafetyAnalysis::run() {
1096
1139
DEBUG_WITH_TYPE (" PrintCFG" , Cfg.dump (AC.getASTContext ().getLangOpts (),
1097
1140
/* ShowColors=*/ true ));
1098
1141
1099
- FactGenerator FactGen (*FactMgr, AC);
1100
- FactGen .run ();
1142
+ FactGenerator FG (*FactMgr, AC);
1143
+ FG .run ();
1101
1144
DEBUG_WITH_TYPE (" LifetimeFacts" , FactMgr->dump (Cfg, AC));
1102
1145
1103
1146
// / TODO(opt): Consider optimizing individual blocks before running the
0 commit comments