@@ -419,10 +419,13 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
419419 VisitedStmts.clear ();
420420 for (unsigned I = 0 ; I < Block->size (); ++I) {
421421 const CFGElement &Element = Block->Elements [I];
422- if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>())
422+ if (std::optional<CFGStmt> CS = Element.getAs <CFGStmt>()) {
423+ DEBUG_WITH_TYPE (" PrintCFG" , llvm::dbgs () << " ================== \n " );
424+ DEBUG_WITH_TYPE (" PrintCFG" , CS->dump ());
425+ DEBUG_WITH_TYPE (" PrintCFG" , CS->getStmt ()->dumpColor ());
423426 Visit (CS->getStmt ());
424- else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
425- Element.getAs <CFGAutomaticObjDtor>())
427+ } else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
428+ Element.getAs <CFGAutomaticObjDtor>())
426429 handleDestructor (*DtorOpt);
427430 }
428431 FactMgr.addBlockFacts (Block, CurrentBlockFacts);
@@ -443,6 +446,31 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
443446 addAssignOriginFact (*VD, *InitExpr);
444447 }
445448
449+ void VisitCXXConstructExpr (const CXXConstructExpr *CCE) {
450+ if (!isGslPointerType (CCE->getType ()))
451+ return ;
452+
453+ if (CCE->getNumArgs () > 0 && hasOrigin (CCE->getArg (0 )->getType ()))
454+ // This is a propagation.
455+ addAssignOriginFact (*CCE, *CCE->getArg (0 ));
456+ else
457+ // This could be a new borrow.
458+ checkForBorrows (CCE, CCE->getConstructor (),
459+ {CCE->getArgs (), CCE->getNumArgs ()});
460+ }
461+
462+ void VisitCXXMemberCallExpr (const CXXMemberCallExpr *MCE) {
463+ if (!isGslPointerType (MCE->getImplicitObjectArgument ()->getType ()))
464+ return ;
465+ // Specifically for conversion operators, like `std::string_view p = a;`
466+ if (isa<CXXConversionDecl>(MCE->getCalleeDecl ())) {
467+ // The argument is the implicit object itself.
468+ checkForBorrows (MCE, MCE->getMethodDecl (),
469+ {MCE->getImplicitObjectArgument ()});
470+ }
471+ // Note: A more general VisitCallExpr could also be used here.
472+ }
473+
446474 void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
447475 // / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
448476 // / pointers can use the same type of loan.
@@ -495,38 +523,131 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
495523 }
496524
497525 void VisitBinaryOperator (const BinaryOperator *BO) {
498- if (BO->isAssignmentOp ()) {
499- const Expr *LHSExpr = BO->getLHS ();
500- const Expr *RHSExpr = BO->getRHS ();
501-
502- // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
503- // LHS must be a pointer/reference type that can be an origin.
504- // RHS must also represent an origin (either another pointer/ref or an
505- // address-of).
506- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
507- if (const auto *VD_LHS =
508- dyn_cast<ValueDecl>(DRE_LHS->getDecl ()->getCanonicalDecl ());
509- VD_LHS && hasOrigin (VD_LHS->getType ()))
510- addAssignOriginFact (*VD_LHS, *RHSExpr);
511- }
526+ if (BO->isAssignmentOp ())
527+ handleAssignment (BO->getLHS (), BO->getRHS ());
528+ }
529+
530+ void VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *OCE) {
531+ if (OCE->isAssignmentOp () && OCE->getNumArgs () == 2 )
532+ handleAssignment (OCE->getArg (0 ), OCE->getArg (1 ));
512533 }
513534
514535 void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
515536 // Check if this is a test point marker. If so, we are done with this
516537 // expression.
517538 if (VisitTestPoint (FCE))
518539 return ;
519- // Visit as normal otherwise.
520- Base::VisitCXXFunctionalCastExpr (FCE);
540+ if (isGslPointerType (FCE->getType ()))
541+ addAssignOriginFact (*FCE, *FCE->getSubExpr ());
542+ }
543+
544+ void VisitInitListExpr (const InitListExpr *ILE) {
545+ if (!hasOrigin (ILE->getType ()))
546+ return ;
547+ // For list initialization with a single element, like `View{...}`, the
548+ // origin of the list itself is the origin of its single element.
549+ if (ILE->getNumInits () == 1 ) {
550+ Visit (ILE->getInit (0 ));
551+ addAssignOriginFact (*ILE, *ILE->getInit (0 ));
552+ }
553+ }
554+
555+ void VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *MTE) {
556+ if (!hasOrigin (MTE->getType ()))
557+ return ;
558+ // A temporary object's origin is the same as the origin of the
559+ // expression that initializes it.
560+ addAssignOriginFact (*MTE, *MTE->getSubExpr ());
521561 }
522562
523563private:
564+ static bool isGslPointerType (QualType QT) {
565+ if (const auto *RD = QT->getAsCXXRecordDecl ()) {
566+ // We need to check the template definition for specializations.
567+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
568+ return CTSD->getSpecializedTemplate ()
569+ ->getTemplatedDecl ()
570+ ->hasAttr <PointerAttr>();
571+ return RD->hasAttr <PointerAttr>();
572+ }
573+ return false ;
574+ }
575+
524576 // Check if a type has an origin.
525- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
577+ static bool hasOrigin (QualType QT) {
578+ if (QT->isFunctionPointerType ())
579+ return false ;
580+ return QT->isPointerOrReferenceType () || isGslPointerType (QT);
581+ }
582+
583+ // / Checks if a call-like expression creates a borrow by passing a local
584+ // / value to a reference parameter, creating an IssueFact if it does.
585+ void checkForBorrows (const Expr *Call, const FunctionDecl *FD,
586+ ArrayRef<const Expr *> Args) {
587+ if (!FD)
588+ return ;
589+
590+ for (unsigned I = 0 ; I < Args.size (); ++I) {
591+ if (I >= FD->getNumParams ())
592+ break ;
593+
594+ const ParmVarDecl *Param = FD->getParamDecl (I);
595+ const Expr *Arg = Args[I];
596+
597+ // This is the core condition for a new borrow: a value type (no origin)
598+ // is passed to a reference parameter.
599+ if (Param->getType ()->isReferenceType () && !hasOrigin (Arg->getType ())) {
600+ if (const Loan *L = createLoanFrom (Arg, Call)) {
601+ OriginID OID = FactMgr.getOriginMgr ().getOrCreate (*Call);
602+ CurrentBlockFacts.push_back (
603+ FactMgr.createFact <IssueFact>(L->ID , OID));
604+ // For view creation, we assume the first borrow is the significant
605+ // one.
606+ return ;
607+ }
608+ }
609+ }
610+ }
611+
612+ // / Attempts to create a loan by analyzing the source expression of a borrow.
613+ // / This method is the single point for creating loans, allowing for future
614+ // / expansion to handle temporaries, field members, etc.
615+ // / \param SourceExpr The expression representing the object being borrowed
616+ // / from.
617+ // / \param IssueExpr The expression that triggers the borrow (e.g., a
618+ // / constructor call).
619+ // / \return The new Loan on success, nullptr on failure.
620+ const Loan *createLoanFrom (const Expr *SourceExpr, const Expr *IssueExpr) {
621+ // For now, we only handle direct borrows from local variables.
622+ // In the future, this can be extended to handle MaterializeTemporaryExpr,
623+ // etc.
624+ if (const auto *DRE =
625+ dyn_cast<DeclRefExpr>(SourceExpr->IgnoreParenImpCasts ())) {
626+ if (const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl ())) {
627+ AccessPath Path (VD);
628+ return &FactMgr.getLoanMgr ().addLoan (Path, IssueExpr);
629+ }
630+ }
631+ return nullptr ;
632+ }
633+
634+ void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
635+ // Find the underlying variable declaration for the left-hand side.
636+ if (const auto *DRE_LHS =
637+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ()))
638+ if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
639+ if (hasOrigin (VD_LHS->getType ()))
640+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
641+ // LHS must be a pointer/reference type that can be an origin.
642+ // RHS must also represent an origin (either another pointer/ref or an
643+ // address-of).
644+ addAssignOriginFact (*VD_LHS, *RHSExpr);
645+ }
526646
527647 template <typename Destination, typename Source>
528648 void addAssignOriginFact (const Destination &D, const Source &S) {
529649 OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
650+ Visit (&S);
530651 OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
531652 CurrentBlockFacts.push_back (
532653 FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
0 commit comments