@@ -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,
@@ -697,6 +740,107 @@ static void transferPointerToBoolean(const ImplicitCastExpr *Expr,
697740 dyn_cast_or_null<BoolValue>(State.Env .getValue (*Expr->getSubExpr ())))
698741 State.Env .setValue (*Expr, *SubExprVal);
699742}
743+ static void handleConstStatusOrAccessorMemberCall (
744+ const CallExpr *Expr, RecordStorageLocation *RecordLoc,
745+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
746+ assert (isStatusOrType (Expr->getType ()));
747+ if (RecordLoc == nullptr )
748+ return ;
749+ const FunctionDecl *DirectCallee = Expr->getDirectCallee ();
750+ if (DirectCallee == nullptr )
751+ return ;
752+ StorageLocation &Loc =
753+ State.Lattice .getOrCreateConstMethodReturnStorageLocation (
754+ *RecordLoc, DirectCallee, State.Env , [&](StorageLocation &Loc) {
755+ initializeStatusOr (cast<RecordStorageLocation>(Loc), State.Env );
756+ });
757+ if (Expr->isPRValue ()) {
758+ auto &ResultLoc = State.Env .getResultObjectLocation (*Expr);
759+ copyRecord (cast<RecordStorageLocation>(Loc), ResultLoc, State.Env );
760+ } else {
761+ State.Env .setStorageLocation (*Expr, Loc);
762+ }
763+ }
764+
765+ static void handleConstStatusOrPointerAccessorMemberCall (
766+ const CallExpr *Expr, RecordStorageLocation *RecordLoc,
767+ const MatchFinder::MatchResult &Result, LatticeTransferState &State) {
768+ if (RecordLoc == nullptr )
769+ return ;
770+ auto *Val = State.Lattice .getOrCreateConstMethodReturnValue (*RecordLoc, Expr,
771+ State.Env );
772+ State.Env .setValue (*Expr, *Val);
773+ }
774+
775+ static void
776+ transferConstStatusOrAccessorMemberCall (const CXXMemberCallExpr *Expr,
777+ const MatchFinder::MatchResult &Result,
778+ LatticeTransferState &State) {
779+ handleConstStatusOrAccessorMemberCall (
780+ Expr, getImplicitObjectLocation (*Expr, State.Env ), Result, State);
781+ }
782+
783+ static void transferConstStatusOrAccessorMemberOperatorCall (
784+ const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result,
785+ LatticeTransferState &State) {
786+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
787+ State.Env .getStorageLocation (*Expr->getArg (0 )));
788+ handleConstStatusOrAccessorMemberCall (Expr, RecordLoc, Result, State);
789+ }
790+
791+ static void transferConstStatusOrPointerAccessorMemberCall (
792+ const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result,
793+ LatticeTransferState &State) {
794+ handleConstStatusOrPointerAccessorMemberCall (
795+ Expr, getImplicitObjectLocation (*Expr, State.Env ), Result, State);
796+ }
797+
798+ static void transferConstStatusOrPointerAccessorMemberOperatorCall (
799+ const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result,
800+ LatticeTransferState &State) {
801+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
802+ State.Env .getStorageLocation (*Expr->getArg (0 )));
803+ handleConstStatusOrPointerAccessorMemberCall (Expr, RecordLoc, Result, State);
804+ }
805+
806+ static void transferStatusOrReturningCall (const CallExpr *Expr,
807+ LatticeTransferState &State) {
808+ RecordStorageLocation *StatusOrLoc =
809+ Expr->isPRValue () ? &State.Env .getResultObjectLocation (*Expr)
810+ : State.Env .get <RecordStorageLocation>(*Expr);
811+ if (StatusOrLoc != nullptr &&
812+ State.Env .getValue (locForOk (locForStatus (*StatusOrLoc))) == nullptr )
813+ initializeStatusOr (*StatusOrLoc, State.Env );
814+ }
815+
816+ static void handleNonConstMemberCall (const CallExpr *Expr,
817+ RecordStorageLocation *RecordLoc,
818+ const MatchFinder::MatchResult &Result,
819+ LatticeTransferState &State) {
820+ if (RecordLoc == nullptr )
821+ return ;
822+ State.Lattice .clearConstMethodReturnValues (*RecordLoc);
823+ State.Lattice .clearConstMethodReturnStorageLocations (*RecordLoc);
824+
825+ if (isStatusOrType (Expr->getType ()))
826+ transferStatusOrReturningCall (Expr, State);
827+ }
828+
829+ static void transferNonConstMemberCall (const CXXMemberCallExpr *Expr,
830+ const MatchFinder::MatchResult &Result,
831+ LatticeTransferState &State) {
832+ handleNonConstMemberCall (Expr, getImplicitObjectLocation (*Expr, State.Env ),
833+ Result, State);
834+ }
835+
836+ static void
837+ transferNonConstMemberOperatorCall (const CXXOperatorCallExpr *Expr,
838+ const MatchFinder::MatchResult &Result,
839+ LatticeTransferState &State) {
840+ auto *RecordLoc = cast_or_null<RecordStorageLocation>(
841+ State.Env .getStorageLocation (*Expr->getArg (0 )));
842+ handleNonConstMemberCall (Expr, RecordLoc, Result, State);
843+ }
700844
701845CFGMatchSwitch<LatticeTransferState>
702846buildTransferMatchSwitch (ASTContext &Ctx,
@@ -755,6 +899,23 @@ buildTransferMatchSwitch(ASTContext &Ctx,
755899 transferLoggingGetReferenceableValueCall)
756900 .CaseOfCFGStmt <CallExpr>(isLoggingCheckEqImpl (),
757901 transferLoggingCheckEqImpl)
902+ // const accessor calls
903+ .CaseOfCFGStmt <CXXMemberCallExpr>(isConstStatusOrAccessorMemberCall (),
904+ transferConstStatusOrAccessorMemberCall)
905+ .CaseOfCFGStmt <CXXOperatorCallExpr>(
906+ isConstStatusOrAccessorMemberOperatorCall (),
907+ transferConstStatusOrAccessorMemberOperatorCall)
908+ .CaseOfCFGStmt <CXXMemberCallExpr>(
909+ isConstStatusOrPointerAccessorMemberCall (),
910+ transferConstStatusOrPointerAccessorMemberCall)
911+ .CaseOfCFGStmt <CXXOperatorCallExpr>(
912+ isConstStatusOrPointerAccessorMemberOperatorCall (),
913+ transferConstStatusOrPointerAccessorMemberOperatorCall)
914+ // non-const member calls that may modify the state of an object.
915+ .CaseOfCFGStmt <CXXMemberCallExpr>(isNonConstMemberCall (),
916+ transferNonConstMemberCall)
917+ .CaseOfCFGStmt <CXXOperatorCallExpr>(isNonConstMemberOperatorCall (),
918+ transferNonConstMemberOperatorCall)
758919 // N.B. These need to come after all other CXXConstructExpr.
759920 // These are there to make sure that every Status and StatusOr object
760921 // have their ok boolean initialized when constructed. If we were to
0 commit comments