@@ -551,83 +551,92 @@ void transferCallReturningOptional(const CallExpr *E,
551551 setHasValue (*Loc, State.Env .makeAtomicBoolValue (), State.Env );
552552}
553553
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,
555558 dataflow::RecordStorageLocation *RecordLoc,
556559 const MatchFinder::MatchResult &Result,
557560 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 ;
582563
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 ()) {
585566 const FunctionDecl *DirectCallee = CE->getDirectCallee ();
586567 if (DirectCallee == nullptr )
587- return ;
568+ return false ;
588569
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+ };
589578 StorageLocation &Loc =
590579 State.Lattice .getOrCreateConstMethodReturnStorageLocation (
591- *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
592- // no-op
593- });
580+ *RecordLoc, DirectCallee, State.Env , Init);
594581
595582 State.Env .setStorageLocation (*CE, Loc);
596- return ;
583+ return true ;
597584 }
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.
603588 Value *Val = State.Lattice .getOrCreateConstMethodReturnValue (*RecordLoc, CE,
604589 State.Env );
605590 if (Val == nullptr )
606- return ;
591+ return false ;
607592 State.Env .setValue (*CE, *Val);
608- return ;
593+ return true ;
609594 }
610-
611- // Perform default handling if the call returns an optional
612- // but wasn't handled above (if RecordLoc is nullptr).
613595 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 ;
615611 }
612+
613+ return false ;
616614}
617615
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 (
622631 MCE, dataflow::getImplicitObjectLocation (*MCE, State.Env ), Result, State);
623632}
624633
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) {
628637 auto *RecordLoc = cast_or_null<dataflow::RecordStorageLocation>(
629638 State.Env .getStorageLocation (*OCE->getArg (0 )));
630- handleConstMemberCall (OCE, RecordLoc, Result, State);
639+ handleConstMemberCallWithFallbacks (OCE, RecordLoc, Result, State);
631640}
632641
633642void handleNonConstMemberCall (const CallExpr *CE,
@@ -1094,9 +1103,9 @@ auto buildTransferMatchSwitch() {
10941103
10951104 // const accessor calls
10961105 .CaseOfCFGStmt <CXXMemberCallExpr>(isZeroParamConstMemberCall (),
1097- transferValue_ConstMemberCall )
1106+ transferConstMemberCall )
10981107 .CaseOfCFGStmt <CXXOperatorCallExpr>(isZeroParamConstMemberOperatorCall (),
1099- transferValue_ConstMemberOperatorCall )
1108+ transferConstMemberOperatorCall )
11001109 // non-const member calls that may modify the state of an object.
11011110 .CaseOfCFGStmt <CXXMemberCallExpr>(isNonConstMemberCall (),
11021111 transferValue_NonConstMemberCall)
0 commit comments