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