@@ -551,83 +551,92 @@ void transferCallReturningOptional(const CallExpr *E,
551
551
setHasValue (*Loc, State.Env .makeAtomicBoolValue (), State.Env );
552
552
}
553
553
554
- void handleConstMemberCall (const CallExpr *CE,
554
+ // Returns true if the const accessor is handled by caching.
555
+ // Returns false if we could not cache. We should perform default handling
556
+ // in that case.
557
+ bool handleConstMemberCall (const CallExpr *CE,
555
558
dataflow::RecordStorageLocation *RecordLoc,
556
559
const MatchFinder::MatchResult &Result,
557
560
LatticeTransferState &State) {
558
- // If the const method returns an optional or reference to an optional.
559
- if (RecordLoc != nullptr && isSupportedOptionalType (CE->getType ())) {
560
- const FunctionDecl *DirectCallee = CE->getDirectCallee ();
561
- if (DirectCallee == nullptr )
562
- return ;
563
- StorageLocation &Loc =
564
- State.Lattice .getOrCreateConstMethodReturnStorageLocation (
565
- *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
566
- setHasValue (cast<RecordStorageLocation>(Loc),
567
- State.Env .makeAtomicBoolValue (), State.Env );
568
- });
569
- if (CE->isGLValue ()) {
570
- // If the call to the const method returns a reference to an optional,
571
- // link the call expression to the cached StorageLocation.
572
- State.Env .setStorageLocation (*CE, Loc);
573
- } else {
574
- // If the call to the const method returns an optional by value, we
575
- // need to use CopyRecord to link the optional to the result object
576
- // of the call expression.
577
- auto &ResultLoc = State.Env .getResultObjectLocation (*CE);
578
- copyRecord (cast<RecordStorageLocation>(Loc), ResultLoc, State.Env );
579
- }
580
- return ;
581
- }
561
+ if (RecordLoc == nullptr )
562
+ return false ;
582
563
583
- // Cache if the const method returns a reference
584
- if (RecordLoc != nullptr && CE->isGLValue ()) {
564
+ // Cache if the const method returns a reference.
565
+ if (CE->isGLValue ()) {
585
566
const FunctionDecl *DirectCallee = CE->getDirectCallee ();
586
567
if (DirectCallee == nullptr )
587
- return ;
568
+ return false ;
588
569
570
+ // Initialize the optional's "has_value" property to true if the type is
571
+ // optional, otherwise no-op. If we want to support const ref to pointers or
572
+ // bools we should initialize their values here too.
573
+ auto Init = [&](StorageLocation &Loc) {
574
+ if (isSupportedOptionalType (CE->getType ()))
575
+ setHasValue (cast<RecordStorageLocation>(Loc),
576
+ State.Env .makeAtomicBoolValue (), State.Env );
577
+ };
589
578
StorageLocation &Loc =
590
579
State.Lattice .getOrCreateConstMethodReturnStorageLocation (
591
- *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
592
- // no-op
593
- });
580
+ *RecordLoc, DirectCallee, State.Env , Init);
594
581
595
582
State.Env .setStorageLocation (*CE, Loc);
596
- return ;
583
+ return true ;
597
584
}
598
-
599
- // Cache if the const method returns a boolean or pointer type.
600
- // We may decide to cache other return types in the future.
601
- if (RecordLoc != nullptr &&
602
- (CE->getType ()->isBooleanType () || CE->getType ()->isPointerType ())) {
585
+ // PRValue cases:
586
+ if (CE->getType ()->isBooleanType () || CE->getType ()->isPointerType ()) {
587
+ // If the const method returns a boolean or pointer type.
603
588
Value *Val = State.Lattice .getOrCreateConstMethodReturnValue (*RecordLoc, CE,
604
589
State.Env );
605
590
if (Val == nullptr )
606
- return ;
591
+ return false ;
607
592
State.Env .setValue (*CE, *Val);
608
- return ;
593
+ return true ;
609
594
}
610
-
611
- // Perform default handling if the call returns an optional
612
- // but wasn't handled above (if RecordLoc is nullptr).
613
595
if (isSupportedOptionalType (CE->getType ())) {
614
- transferCallReturningOptional (CE, Result, State);
596
+ // If the const method returns an optional by value.
597
+ const FunctionDecl *DirectCallee = CE->getDirectCallee ();
598
+ if (DirectCallee == nullptr )
599
+ return false ;
600
+ StorageLocation &Loc =
601
+ State.Lattice .getOrCreateConstMethodReturnStorageLocation (
602
+ *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
603
+ setHasValue (cast<RecordStorageLocation>(Loc),
604
+ State.Env .makeAtomicBoolValue (), State.Env );
605
+ });
606
+ // Use copyRecord to link the optional to the result object of the call
607
+ // expression.
608
+ auto &ResultLoc = State.Env .getResultObjectLocation (*CE);
609
+ copyRecord (cast<RecordStorageLocation>(Loc), ResultLoc, State.Env );
610
+ return true ;
615
611
}
612
+
613
+ return false ;
616
614
}
617
615
618
- void transferValue_ConstMemberCall (const CXXMemberCallExpr *MCE,
619
- const MatchFinder::MatchResult &Result,
620
- LatticeTransferState &State) {
621
- handleConstMemberCall (
616
+ void handleConstMemberCallWithFallbacks (
617
+ const CallExpr *CE, dataflow::RecordStorageLocation *RecordLoc,
618
+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
619
+ if (handleConstMemberCall (CE, RecordLoc, Result, State))
620
+ return ;
621
+ // Perform default handling if the call returns an optional, but wasn't
622
+ // handled by caching.
623
+ if (isSupportedOptionalType (CE->getType ()))
624
+ transferCallReturningOptional (CE, Result, State);
625
+ }
626
+
627
+ void transferConstMemberCall (const CXXMemberCallExpr *MCE,
628
+ const MatchFinder::MatchResult &Result,
629
+ LatticeTransferState &State) {
630
+ handleConstMemberCallWithFallbacks (
622
631
MCE, dataflow::getImplicitObjectLocation (*MCE, State.Env ), Result, State);
623
632
}
624
633
625
- void transferValue_ConstMemberOperatorCall (
626
- const CXXOperatorCallExpr *OCE, const MatchFinder::MatchResult &Result,
627
- LatticeTransferState &State) {
634
+ void transferConstMemberOperatorCall ( const CXXOperatorCallExpr *OCE,
635
+ const MatchFinder::MatchResult &Result,
636
+ LatticeTransferState &State) {
628
637
auto *RecordLoc = cast_or_null<dataflow::RecordStorageLocation>(
629
638
State.Env .getStorageLocation (*OCE->getArg (0 )));
630
- handleConstMemberCall (OCE, RecordLoc, Result, State);
639
+ handleConstMemberCallWithFallbacks (OCE, RecordLoc, Result, State);
631
640
}
632
641
633
642
void handleNonConstMemberCall (const CallExpr *CE,
@@ -1094,9 +1103,9 @@ auto buildTransferMatchSwitch() {
1094
1103
1095
1104
// const accessor calls
1096
1105
.CaseOfCFGStmt <CXXMemberCallExpr>(isZeroParamConstMemberCall (),
1097
- transferValue_ConstMemberCall )
1106
+ transferConstMemberCall )
1098
1107
.CaseOfCFGStmt <CXXOperatorCallExpr>(isZeroParamConstMemberOperatorCall (),
1099
- transferValue_ConstMemberOperatorCall )
1108
+ transferConstMemberOperatorCall )
1100
1109
// non-const member calls that may modify the state of an object.
1101
1110
.CaseOfCFGStmt <CXXMemberCallExpr>(isNonConstMemberCall (),
1102
1111
transferValue_NonConstMemberCall)
0 commit comments