diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp index 2741476fe4781..8af12139d181f 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp @@ -150,6 +150,24 @@ static auto isComparisonOperatorCall(llvm::StringRef operator_name) { hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType())))); } +static auto isOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasName("::absl::OkStatus")))); +} + +static auto isNotOkStatusCall() { + using namespace ::clang::ast_matchers; // NOLINT: Too many names + return callExpr(callee(functionDecl(hasAnyName( + "::absl::AbortedError", "::absl::AlreadyExistsError", + "::absl::CancelledError", "::absl::DataLossError", + "::absl::DeadlineExceededError", "::absl::FailedPreconditionError", + "::absl::InternalError", "::absl::InvalidArgumentError", + "::absl::NotFoundError", "::absl::OutOfRangeError", + "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError", + "::absl::UnauthenticatedError", "::absl::UnavailableError", + "::absl::UnimplementedError", "::absl::UnknownError")))); +} + static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options) { return CFGMatchSwitchBuilder buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder Builder) { @@ -453,6 +488,8 @@ buildTransferMatchSwitch(ASTContext &Ctx, transferComparisonOperator(Expr, State, /*IsNegative=*/true); }) + .CaseOfCFGStmt(isOkStatusCall(), transferOkStatusCall) + .CaseOfCFGStmt(isNotOkStatusCall(), transferNotOkStatusCall) .Build(); } diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp index d3dee58651396..461af73ea6c01 100644 --- a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp @@ -1356,7 +1356,7 @@ bool operator==(const Status &lhs, const Status &rhs); bool operator!=(const Status &lhs, const Status &rhs); Status OkStatus(); -Status InvalidArgumentError(char *); +Status InvalidArgumentError(const char *); #endif // STATUS_H )cc"; diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index d3b10688643b5..2676dab7fd904 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -2710,6 +2710,36 @@ TEST_P(UncheckedStatusOrAccessModelTest, EqualityCheck) { } } )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() == absl::OkStatus()) + sor.value(); + else + sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::OkStatus()) + sor.value(); // [[unsafe]] + else + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::InvalidArgumentError("oh no")) + sor.value(); // [[unsafe]] + else + sor.value(); // [[unsafe]] + } + )cc"); ExpectDiagnosticsFor( R"cc( #include "unchecked_statusor_access_test_defs.h"