@@ -237,6 +237,49 @@ static auto isAsStatusCallWithStatusOr() {
237237 hasArgument (0 , hasType (statusOrType ())));
238238}
239239
240+ static auto possiblyReferencedStatusOrType () {
241+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
242+ return anyOf (statusOrType (), referenceType (pointee (statusOrType ())));
243+ }
244+
245+ static auto isConstStatusOrAccessorMemberCall () {
246+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
247+ return cxxMemberCallExpr (callee (
248+ cxxMethodDecl (parameterCountIs (0 ), isConst (),
249+ returns (qualType (possiblyReferencedStatusOrType ())))));
250+ }
251+
252+ static auto isConstStatusOrAccessorMemberOperatorCall () {
253+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
254+ return cxxOperatorCallExpr (
255+ callee (cxxMethodDecl (parameterCountIs (0 ), isConst (),
256+ returns (possiblyReferencedStatusOrType ()))));
257+ }
258+
259+ static auto isConstStatusOrPointerAccessorMemberCall () {
260+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
261+ return cxxMemberCallExpr (callee (cxxMethodDecl (
262+ parameterCountIs (0 ), isConst (),
263+ returns (pointerType (pointee (possiblyReferencedStatusOrType ()))))));
264+ }
265+
266+ static auto isConstStatusOrPointerAccessorMemberOperatorCall () {
267+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
268+ return cxxOperatorCallExpr (callee (cxxMethodDecl (
269+ parameterCountIs (0 ), isConst (),
270+ returns (pointerType (pointee (possiblyReferencedStatusOrType ()))))));
271+ }
272+
273+ static auto isNonConstMemberCall () {
274+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
275+ return cxxMemberCallExpr (callee (cxxMethodDecl (unless (isConst ()))));
276+ }
277+
278+ static auto isNonConstMemberOperatorCall () {
279+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
280+ return cxxOperatorCallExpr (callee (cxxMethodDecl (unless (isConst ()))));
281+ }
282+
240283static auto
241284buildDiagnoseMatchSwitch (const UncheckedStatusOrAccessModelOptions &Options) {
242285 return CFGMatchSwitchBuilder<const Environment,
@@ -698,6 +741,114 @@ static void transferPointerToBoolean(const ImplicitCastExpr *Expr,
698741 State.Env .setValue (*Expr, *SubExprVal);
699742}
700743
744+ static void transferStatusOrReturningCall (const CallExpr *Expr,
745+ LatticeTransferState &State) {
746+ RecordStorageLocation *StatusOrLoc =
747+ Expr->isPRValue () ? &State.Env .getResultObjectLocation (*Expr)
748+ : State.Env .get <RecordStorageLocation>(*Expr);
749+ if (StatusOrLoc != nullptr &&
750+ State.Env .getValue (locForOk (locForStatus (*StatusOrLoc))) == nullptr )
751+ initializeStatusOr (*StatusOrLoc, State.Env );
752+ }
753+
754+ static bool doHandleConstStatusOrAccessorMemberCall (
755+ const CallExpr *Expr, RecordStorageLocation *RecordLoc,
756+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
757+ assert (isStatusOrType (Expr->getType ()));
758+ if (RecordLoc == nullptr )
759+ return false ;
760+ const FunctionDecl *DirectCallee = Expr->getDirectCallee ();
761+ if (DirectCallee == nullptr )
762+ return false ;
763+ StorageLocation &Loc =
764+ State.Lattice .getOrCreateConstMethodReturnStorageLocation (
765+ *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
766+ initializeStatusOr (cast<RecordStorageLocation>(Loc), State.Env );
767+ });
768+ if (Expr->isPRValue ()) {
769+ auto &ResultLoc = State.Env .getResultObjectLocation (*Expr);
770+ copyRecord (cast<RecordStorageLocation>(Loc), ResultLoc, State.Env );
771+ } else {
772+ State.Env .setStorageLocation (*Expr, Loc);
773+ }
774+ return true ;
775+ }
776+
777+ static void handleConstStatusOrAccessorMemberCall (
778+ const CallExpr *Expr, RecordStorageLocation *RecordLoc,
779+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
780+ if (!doHandleConstStatusOrAccessorMemberCall (Expr, RecordLoc, Result, State))
781+ transferStatusOrReturningCall (Expr, State);
782+ }
783+ static void handleConstStatusOrPointerAccessorMemberCall (
784+ const CallExpr *Expr, RecordStorageLocation *RecordLoc,
785+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
786+ if (RecordLoc == nullptr )
787+ return ;
788+ auto *Val = State.Lattice .getOrCreateConstMethodReturnValue (*RecordLoc, Expr,
789+ State.Env );
790+ State.Env .setValue (*Expr, *Val);
791+ }
792+
793+ static void
794+ transferConstStatusOrAccessorMemberCall (const CXXMemberCallExpr *Expr,
795+ const MatchFinder::MatchResult &Result,
796+ LatticeTransferState &State) {
797+ handleConstStatusOrAccessorMemberCall (
798+ Expr, getImplicitObjectLocation (*Expr, State.Env ), Result, State);
799+ }
800+
801+ static void transferConstStatusOrAccessorMemberOperatorCall (
802+ const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result,
803+ LatticeTransferState &State) {
804+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
805+ State.Env .getStorageLocation (*Expr->getArg (0 )));
806+ handleConstStatusOrAccessorMemberCall (Expr, RecordLoc, Result, State);
807+ }
808+
809+ static void transferConstStatusOrPointerAccessorMemberCall (
810+ const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result,
811+ LatticeTransferState &State) {
812+ handleConstStatusOrPointerAccessorMemberCall (
813+ Expr, getImplicitObjectLocation (*Expr, State.Env ), Result, State);
814+ }
815+
816+ static void transferConstStatusOrPointerAccessorMemberOperatorCall (
817+ const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result,
818+ LatticeTransferState &State) {
819+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
820+ State.Env .getStorageLocation (*Expr->getArg (0 )));
821+ handleConstStatusOrPointerAccessorMemberCall (Expr, RecordLoc, Result, State);
822+ }
823+
824+ static void handleNonConstMemberCall (const CallExpr *Expr,
825+ RecordStorageLocation *RecordLoc,
826+ const MatchFinder::MatchResult &Result,
827+ LatticeTransferState &State) {
828+ if (RecordLoc) {
829+ State.Lattice .clearConstMethodReturnValues (*RecordLoc);
830+ State.Lattice .clearConstMethodReturnStorageLocations (*RecordLoc);
831+ }
832+ if (isStatusOrType (Expr->getType ()))
833+ transferStatusOrReturningCall (Expr, State);
834+ }
835+
836+ static void transferNonConstMemberCall (const CXXMemberCallExpr *Expr,
837+ const MatchFinder::MatchResult &Result,
838+ LatticeTransferState &State) {
839+ handleNonConstMemberCall (Expr, getImplicitObjectLocation (*Expr, State.Env ),
840+ Result, State);
841+ }
842+
843+ static void
844+ transferNonConstMemberOperatorCall (const CXXOperatorCallExpr *Expr,
845+ const MatchFinder::MatchResult &Result,
846+ LatticeTransferState &State) {
847+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
848+ State.Env .getStorageLocation (*Expr->getArg (0 )));
849+ handleNonConstMemberCall (Expr, RecordLoc, Result, State);
850+ }
851+
701852CFGMatchSwitch<LatticeTransferState>
702853buildTransferMatchSwitch (ASTContext &Ctx,
703854 CFGMatchSwitchBuilder<LatticeTransferState> Builder) {
@@ -755,6 +906,23 @@ buildTransferMatchSwitch(ASTContext &Ctx,
755906 transferLoggingGetReferenceableValueCall)
756907 .CaseOfCFGStmt <CallExpr>(isLoggingCheckEqImpl (),
757908 transferLoggingCheckEqImpl)
909+ // const accessor calls
910+ .CaseOfCFGStmt <CXXMemberCallExpr>(isConstStatusOrAccessorMemberCall (),
911+ transferConstStatusOrAccessorMemberCall)
912+ .CaseOfCFGStmt <CXXOperatorCallExpr>(
913+ isConstStatusOrAccessorMemberOperatorCall (),
914+ transferConstStatusOrAccessorMemberOperatorCall)
915+ .CaseOfCFGStmt <CXXMemberCallExpr>(
916+ isConstStatusOrPointerAccessorMemberCall (),
917+ transferConstStatusOrPointerAccessorMemberCall)
918+ .CaseOfCFGStmt <CXXOperatorCallExpr>(
919+ isConstStatusOrPointerAccessorMemberOperatorCall (),
920+ transferConstStatusOrPointerAccessorMemberOperatorCall)
921+ // non-const member calls that may modify the state of an object.
922+ .CaseOfCFGStmt <CXXMemberCallExpr>(isNonConstMemberCall (),
923+ transferNonConstMemberCall)
924+ .CaseOfCFGStmt <CXXOperatorCallExpr>(isNonConstMemberOperatorCall (),
925+ transferNonConstMemberOperatorCall)
758926 // N.B. These need to come after all other CXXConstructExpr.
759927 // These are there to make sure that every Status and StatusOr object
760928 // have their ok boolean initialized when constructed. If we were to
0 commit comments