@@ -351,6 +351,25 @@ static auto isAssertionResultConstructFromBoolCall() {
351351 hasArgument (0 , hasType (booleanType ())));
352352}
353353
354+ static auto isStatusOrReturningCall () {
355+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
356+ return callExpr (
357+ callee (functionDecl (returns (possiblyReferencedStatusOrType ()))));
358+ }
359+
360+ static auto isStatusOrPtrReturningCall () {
361+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
362+ return callExpr (callee (functionDecl (returns (hasUnqualifiedDesugaredType (
363+ pointerType (pointee (possiblyReferencedStatusOrType ())))))));
364+ }
365+
366+ static auto isStatusPtrReturningCall () {
367+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
368+ return callExpr (callee (functionDecl (returns (hasUnqualifiedDesugaredType (
369+ pointerType (pointee (hasUnqualifiedDesugaredType (
370+ recordType (hasDeclaration (statusClass ()))))))))));
371+ }
372+
354373static auto
355374buildDiagnoseMatchSwitch (const UncheckedStatusOrAccessModelOptions &Options) {
356375 return CFGMatchSwitchBuilder<const Environment,
@@ -1074,6 +1093,40 @@ static void transferValueCall(const CXXMemberCallExpr *Expr,
10741093 StatusOrLoc->getSyntheticField (" value" ));
10751094}
10761095
1096+ static void transferStatusOrPtrReturningCall (const CallExpr *Expr,
1097+ const MatchFinder::MatchResult &,
1098+ LatticeTransferState &State) {
1099+ PointerValue *PointerVal =
1100+ dyn_cast_or_null<PointerValue>(State.Env .getValue (*Expr));
1101+ if (!PointerVal) {
1102+ PointerVal = cast<PointerValue>(State.Env .createValue (Expr->getType ()));
1103+ State.Env .setValue (*Expr, *PointerVal);
1104+ }
1105+
1106+ auto *RecordLoc =
1107+ dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc ());
1108+ if (RecordLoc != nullptr &&
1109+ State.Env .getValue (locForOk (locForStatus (*RecordLoc))) == nullptr )
1110+ initializeStatusOr (*RecordLoc, State.Env );
1111+ }
1112+
1113+ static void transferStatusPtrReturningCall (const CallExpr *Expr,
1114+ const MatchFinder::MatchResult &,
1115+ LatticeTransferState &State) {
1116+ PointerValue *PointerVal =
1117+ dyn_cast_or_null<PointerValue>(State.Env .getValue (*Expr));
1118+ if (!PointerVal) {
1119+ PointerVal = cast<PointerValue>(State.Env .createValue (Expr->getType ()));
1120+ State.Env .setValue (*Expr, *PointerVal);
1121+ }
1122+
1123+ auto *RecordLoc =
1124+ dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc ());
1125+ if (RecordLoc != nullptr &&
1126+ State.Env .getValue (locForOk (*RecordLoc)) == nullptr )
1127+ initializeStatus (*RecordLoc, State.Env );
1128+ }
1129+
10771130static RecordStorageLocation *
10781131getSmartPtrLikeStorageLocation (const Expr &E, const Environment &Env) {
10791132 if (!E.isPRValue ())
@@ -1228,6 +1281,18 @@ buildTransferMatchSwitch(ASTContext &Ctx,
12281281 transferNonConstMemberCall)
12291282 .CaseOfCFGStmt <CXXOperatorCallExpr>(isNonConstMemberOperatorCall (),
12301283 transferNonConstMemberOperatorCall)
1284+ // N.B. this has to be after transferConstMemberCall, otherwise we would
1285+ // always return a fresh RecordStorageLocation for the StatusOr.
1286+ .CaseOfCFGStmt <CallExpr>(isStatusOrReturningCall (),
1287+ [](const CallExpr *Expr,
1288+ const MatchFinder::MatchResult &,
1289+ LatticeTransferState &State) {
1290+ transferStatusOrReturningCall (Expr, State);
1291+ })
1292+ .CaseOfCFGStmt <CallExpr>(isStatusOrPtrReturningCall (),
1293+ transferStatusOrPtrReturningCall)
1294+ .CaseOfCFGStmt <CallExpr>(isStatusPtrReturningCall (),
1295+ transferStatusPtrReturningCall)
12311296 // N.B. These need to come after all other CXXConstructExpr.
12321297 // These are there to make sure that every Status and StatusOr object
12331298 // have their ok boolean initialized when constructed. If we were to
0 commit comments