3336 lines
77 KiB
C++
3336 lines
77 KiB
C++
//===- UncheckedStatusOrAccessModelTestFixture.cpp ------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "UncheckedStatusOrAccessModelTestFixture.h"
|
|
#include "MockHeaders.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace clang::dataflow::statusor_model {
|
|
namespace {
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, NoStatusOrMention) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
void target() { "nop"; }
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToValue) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, NonExplicitInitialization) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
STATUSOR_INT target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
return x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToValue_NewLine) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor. // force newline
|
|
value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Rvalue_CallToValue) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
std::move(sor).value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToValueOrDie) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.ValueOrDie(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Rvalue_CallToValueOrDie) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
std::move(sor).ValueOrDie(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToOperatorStar) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
*sor; // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToOperatorStarSeparateLine) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
* // [[unsafe]]
|
|
sor;
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Rvalue_CallToOperatorStar) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
*std::move(sor); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Lvalue_CallToOperatorArrow) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
void foo();
|
|
};
|
|
|
|
void target(absl::StatusOr<Foo> sor) {
|
|
sor->foo(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest,
|
|
UnwrapWithoutCheck_Rvalue_CallToOperatorArrow) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
void foo();
|
|
};
|
|
|
|
void target(absl::StatusOr<Foo> sor) {
|
|
std::move(sor)->foo(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, UnwrapRvalueWithCheck) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok()) std::move(sor).value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ParensInDeclInitExpr) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
auto sor = (Make<STATUSOR_INT>());
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ReferenceInDeclInitExpr) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
const STATUSOR_INT& GetStatusOrInt() const;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
auto sor = foo.GetStatusOrInt();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT& GetStatusOrInt();
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
auto sor = foo.GetStatusOrInt();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT&& GetStatusOrInt() &&;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
auto sor = std::move(foo).GetStatusOrInt();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
if (auto sor = Make<STATUSOR_INT>(); sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, JoinSafeSafe) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor, bool b) {
|
|
if (sor.ok()) {
|
|
if (b)
|
|
sor.value();
|
|
else
|
|
sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, JoinUnsafeUnsafe) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor, bool b) {
|
|
if (b)
|
|
sor.value(); // [[unsafe]]
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, InversedIfThenElse) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok())
|
|
sor.value(); // [[unsafe]]
|
|
else
|
|
sor.value();
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, DoubleInversedIfThenElse) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!!sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TripleInversedIfThenElse) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!!!sor.ok())
|
|
sor.value(); // [[unsafe]]
|
|
else
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_LhsAndRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok() && y.ok()) {
|
|
x.value();
|
|
|
|
y.value();
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_NotLhsAndRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!x.ok() && y.ok()) {
|
|
y.value();
|
|
|
|
x.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_LhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok() && !y.ok()) {
|
|
x.value();
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_NotLhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!x.ok() && !y.ok()) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_LhsAndRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(x.ok() && y.ok())) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_NotLhsAndRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(!x.ok() && y.ok())) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
y.value();
|
|
|
|
x.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_LhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(x.ok() && !y.ok())) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value();
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_NotLhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(!x.ok() && !y.ok())) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_LhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok() || y.ok()) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_NotLhsOrRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!x.ok() || y.ok()) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value();
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_LhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok() || !y.ok()) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
y.value();
|
|
|
|
x.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_NotLhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!x.ok() || !y.ok()) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_LhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(x.ok() || y.ok())) {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_NotLhsOrRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(!x.ok() || y.ok())) {
|
|
x.value();
|
|
|
|
y.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_LhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(x.ok() || !y.ok())) {
|
|
y.value();
|
|
|
|
x.value(); // [[unsafe]]
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, IfThenElse_Not_NotLhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!(!x.ok() || !y.ok())) {
|
|
x.value();
|
|
|
|
y.value();
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TerminatingIfThenBranch) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) return;
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok()) return;
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!x.ok() || !y.ok()) return;
|
|
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TerminatingIfElseBranch) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok()) {
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) {
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TerminatingIfThenBranchInLoop) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (Make<bool>()) {
|
|
if (!sor.ok()) continue;
|
|
|
|
sor.value();
|
|
}
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (Make<bool>()) {
|
|
if (!sor.ok()) break;
|
|
|
|
sor.value();
|
|
}
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TernaryConditionalOperator) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.ok() ? sor.value() : 21;
|
|
|
|
sor.ok() ? 21 : sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
!sor.ok() ? 21 : sor.value();
|
|
|
|
!sor.ok() ? sor.value() : 21; // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
!((__builtin_expect(false || (!(sor1.ok() && sor2.ok())), false)))
|
|
? (void)0
|
|
: (void)1;
|
|
do {
|
|
sor1.value(); // [[unsafe]]
|
|
sor2.value(); // [[unsafe]]
|
|
} while (true);
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (Make<bool>()) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (!sor.ok()) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (!!sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (!!!sor.ok()) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_LhsAndRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() && y.ok()) {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_NotLhsAndRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() && y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() && y.ok()) y.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_LhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() && !y.ok()) x.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() && !y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_NotLhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() && !y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() && !y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_LhsAndRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() && y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() && y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_NotLhsAndRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() && y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() && y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_LhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() && !y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() && !y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_NotLhsAndNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() && !y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() && !y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_LhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() || y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() || y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_NotLhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() || y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() || y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_LhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() || !y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (x.ok() || !y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_NotLhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() || !y.ok()) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!x.ok() || !y.ok()) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_LhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() || y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() || y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_NotLhsOrRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() || y.ok())) x.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() || y.ok())) y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_LhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() || !y.ok())) x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(x.ok() || !y.ok())) y.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_Not_NotLhsOrNotRhs) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (!(!x.ok() || !y.ok())) {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_AccessAfterStmt) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (sor.ok()) {
|
|
}
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (!sor.ok()) {
|
|
}
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_TerminatingBranch_Return) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (!sor.ok()) return;
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (sor.ok()) return;
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, While_NestedIfWithBinaryCondition) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (Make<bool>()) {
|
|
if (x.ok() && y.ok()) {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
while (Make<bool>()) {
|
|
if (!(!x.ok() || !y.ok())) {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, BuiltinExpect) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (!__builtin_expect(!x.ok() || __builtin_expect(!y.ok(), true), false)) {
|
|
x.value();
|
|
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CopyAssignment) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
if (sor.ok()) {
|
|
sor = Make<STATUSOR_INT>();
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
if (!sor.ok()) return;
|
|
|
|
sor = Make<STATUSOR_INT>();
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
if (x.ok()) {
|
|
STATUSOR_INT y = x;
|
|
x = Make<STATUSOR_INT>();
|
|
|
|
y.value();
|
|
|
|
x.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
STATUSOR_INT y = x;
|
|
if (!y.ok()) return;
|
|
|
|
x.value();
|
|
|
|
y = Make<STATUSOR_INT>();
|
|
x.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT bar;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
foo.bar = Make<STATUSOR_INT>();
|
|
if (foo.bar.ok()) {
|
|
foo.bar.value();
|
|
|
|
foo.bar = Make<STATUSOR_INT>();
|
|
foo.bar.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ShortCircuitingBinaryOperators) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_BOOL sor) {
|
|
bool b = sor.ok() & sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_BOOL sor) {
|
|
bool b = sor.ok() && sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_BOOL sor) {
|
|
bool b = !sor.ok() && sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_BOOL sor) {
|
|
bool b = sor.ok() || sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_BOOL sor) {
|
|
bool b = !sor.ok() || sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (b || sor.ok()) {
|
|
do {
|
|
sor.value(); // [[unsafe]]
|
|
} while (true);
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (__builtin_expect(b || sor.ok(), false)) {
|
|
do {
|
|
sor.value(); // [[unsafe]]
|
|
} while (false);
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
while (sor1.ok() && sor2.ok()) sor1.value();
|
|
while (sor1.ok() && sor2.ok()) sor2.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, References) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
STATUSOR_INT& y = x;
|
|
if (x.ok()) {
|
|
x.value();
|
|
|
|
y.value();
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
STATUSOR_INT& y = x;
|
|
if (y.ok()) {
|
|
x.value();
|
|
|
|
y.value();
|
|
} else {
|
|
x.value(); // [[unsafe]]
|
|
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
STATUSOR_INT& y = x;
|
|
if (!y.ok()) return;
|
|
|
|
x.value();
|
|
|
|
y = Make<STATUSOR_INT>();
|
|
x.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT x = Make<STATUSOR_INT>();
|
|
const STATUSOR_INT& y = x;
|
|
if (!y.ok()) return;
|
|
|
|
y.value();
|
|
|
|
x = Make<STATUSOR_INT>();
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, NoReturnAttribute) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
__attribute__((noreturn)) void f();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) f();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void f();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) f();
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
__attribute__((noreturn)) ~Foo();
|
|
void Bar();
|
|
};
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) Foo().Bar();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
~Foo();
|
|
void Bar();
|
|
};
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) Foo().Bar();
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void f();
|
|
__attribute__((noreturn)) void g();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.ok() ? f() : g();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
__attribute__((noreturn)) void f();
|
|
void g();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
!sor.ok() ? f() : g();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void f();
|
|
void g();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.ok() ? f() : g();
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void terminate() __attribute__((noreturn));
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.value(); // [[unsafe]]
|
|
terminate();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void terminate() __attribute__((noreturn));
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok()) sor.value();
|
|
terminate();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void terminate() __attribute__((noreturn));
|
|
|
|
struct Foo {
|
|
~Foo() __attribute__((noreturn));
|
|
};
|
|
|
|
void target() {
|
|
auto sor = Make<absl::StatusOr<Foo>>();
|
|
!(false || !(sor.ok())) ? (void)0 : terminate();
|
|
sor.value();
|
|
terminate();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, DeclInLoop) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (auto ok = sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
using BoolAlias = bool;
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
while (BoolAlias ok = sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
while (Make<bool>()) {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
using StatusOrInt = STATUSOR_INT;
|
|
|
|
void target() {
|
|
while (Make<bool>()) {
|
|
StatusOrInt sor = Make<STATUSOR_INT>();
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, NonEvaluatedExprInCondition) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
bool unknown();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (unknown() && sor.ok()) sor.value();
|
|
if (sor.ok() && unknown()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
bool unknown();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!(!unknown() || !sor.ok())) sor.value();
|
|
if (!(!sor.ok() || !unknown())) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
bool unknown();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (unknown() || sor.ok()) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
bool unknown();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok() || unknown()) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CorrelatedBranches) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (b || sor.ok()) {
|
|
if (!b) sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (b && !sor.ok()) return;
|
|
if (b) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (sor.ok()) b = true;
|
|
if (b) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (b) return;
|
|
if (sor.ok()) b = true;
|
|
if (b) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ConditionWithInitStmt) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
if (STATUSOR_INT sor = Make<STATUSOR_INT>(); sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
if (STATUSOR_INT sor = Make<STATUSOR_INT>(); !sor.ok())
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, DeadCode) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
bool b = false;
|
|
if (b) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
bool b;
|
|
b = false;
|
|
if (b) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, TemporaryDestructors) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
sor.ok() ? sor.value() : Fatal().value();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
!sor.ok() ? Fatal().value() : sor.value();
|
|
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
b ? 0 : sor.ok() ? sor.value() : Fatal().value();
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
for (int i = 0; i < 10; i++) {
|
|
(b && sor.ok()) ? sor.value() : Fatal().value();
|
|
|
|
if (b) sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
for (int i = 0; i < 10; i++) {
|
|
(b || !sor.ok()) ? Fatal().value() : 0;
|
|
|
|
if (!b) sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
for (int i = 0; i < 10; i++) {
|
|
(false || !(b && sor.ok())) ? Fatal().value() : 0;
|
|
|
|
do {
|
|
sor.value();
|
|
} while (b);
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CheckMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK(sor.ok());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK(!sor.ok());
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, QcheckMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK(sor.ok());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK(!sor.ok());
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CheckOkMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK_OK(sor.status());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK_OK(sor);
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUS s = Make<STATUS>();
|
|
CHECK_OK(s);
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, QcheckOkMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK_OK(sor.status());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK_OK(sor);
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUS s = Make<STATUS>();
|
|
QCHECK_OK(s);
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CheckEqMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK_EQ(sor.status(), absl::OkStatus());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
CHECK_EQ(Make<STATUS>(), absl::OkStatus());
|
|
CHECK_EQ(absl::OkStatus(), Make<STATUS>());
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, QcheckEqMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK_EQ(sor.status(), absl::OkStatus());
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, CheckNeMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
CHECK_NE(sor.status(), absl::OkStatus());
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, QcheckNeMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
QCHECK_NE(sor.status(), absl::OkStatus());
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, GlobalVars) {
|
|
// The following examples are not sound as there could be opaque calls between
|
|
// the ok() and the value() calls that change the StatusOr value.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
static STATUSOR_INT sor;
|
|
|
|
void target() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
static STATUSOR_INT sor;
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
static STATUSOR_INT sor;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
if (foo.sor.ok())
|
|
foo.sor.value();
|
|
else
|
|
foo.sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
static STATUSOR_INT sor;
|
|
};
|
|
|
|
void target() {
|
|
if (Foo::sor.ok())
|
|
Foo::sor.value();
|
|
else
|
|
Foo::sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
static STATUSOR_INT sor;
|
|
|
|
static void target() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
};
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
static STATUSOR_INT sor;
|
|
|
|
void target() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
};
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct S {
|
|
static const int x = -1;
|
|
};
|
|
|
|
int target(S s) { return s.x; }
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ReferenceReceivers) {
|
|
// The following examples are not sound as there could be opaque calls between
|
|
// the ok() and the value() calls that change the StatusOr value. However,
|
|
// this is the behavior that users expect so it is here to stay.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT& sor) {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT& sor;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
if (foo.sor.ok())
|
|
foo.sor.value();
|
|
else
|
|
foo.sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Bar {
|
|
STATUSOR_INT sor;
|
|
};
|
|
|
|
struct Foo {
|
|
Bar& bar;
|
|
};
|
|
|
|
void target(Foo foo) {
|
|
if (foo.bar.sor.ok())
|
|
foo.bar.sor.value();
|
|
else
|
|
foo.bar.sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT& sor;
|
|
};
|
|
|
|
void target(Foo& foo) {
|
|
if (foo.sor.ok())
|
|
foo.sor.value();
|
|
else
|
|
foo.sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, Lambdas) {
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
[](STATUSOR_INT sor) {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}(Make<STATUSOR_INT>());
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
[sor]() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
[&sor]() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
[sor2 = sor]() {
|
|
if (sor2.ok())
|
|
sor2.value();
|
|
else
|
|
sor2.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
[&]() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
[=]() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsForLambda(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
STATUSOR_INT sor;
|
|
|
|
void target() {
|
|
[this]() {
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}();
|
|
}
|
|
};
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, GoodLambda) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
int target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
if (sor.ok()) return [&s = sor.value()] { return s; }();
|
|
return 0;
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, Status) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void foo();
|
|
|
|
void target(STATUS s) {
|
|
if (s.ok()) foo();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void foo();
|
|
|
|
void target() {
|
|
STATUS s = Make<STATUSOR_INT>().status();
|
|
if (s.ok()) foo();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ExpectThatMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
EXPECT_THAT(sor, testing::status::IsOk());
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
EXPECT_THAT(sor.status(), testing::status::IsOk());
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
EXPECT_THAT(sor, testing::status::IsOk());
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ExpectOkMacro) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
EXPECT_OK(sor);
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
EXPECT_OK(sor.status());
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
EXPECT_OK(sor);
|
|
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, BreadthFirstBlockTraversalLoop) {
|
|
// Evaluating the CFG blocks of the code below in breadth-first order results
|
|
// in an infinite loop. Each iteration of the while loop below results in a
|
|
// new value being assigned to the storage location of sor1. However,
|
|
// following a bread-first order of evaluation, downstream blocks will join
|
|
// environments of different generations of predecessor blocks having distinct
|
|
// values assigned to the sotrage location of sor1, resulting in not assigning
|
|
// a value to the storage location of sor1 in successors. As iterations of the
|
|
// analysis go, the state of the environment flips between having a value
|
|
// assigned to the storage location of sor1 and not having a value assigned to
|
|
// it. Since the evaluation of the copy constructor expression in bar(sor1)
|
|
// depends on a value being assigned to sor1, the state of the environment
|
|
// also flips between having a storage location assigned to the bar(sor1)
|
|
// expression and not having a storage location assigned to it. This leads to
|
|
// an infinite loop as the environment can't stabilize.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void foo(int, int);
|
|
STATUSOR_INT bar(STATUSOR_INT);
|
|
void baz(int);
|
|
|
|
void target() {
|
|
while (true) {
|
|
STATUSOR_INT sor1 = Make<STATUSOR_INT>();
|
|
if (sor1.ok()) {
|
|
STATUSOR_INT sor2 = Make<STATUSOR_INT>();
|
|
if (sor2.ok()) foo(sor1.value(), sor2.value());
|
|
}
|
|
|
|
STATUSOR_INT sor3 = bar(sor1);
|
|
for (int i = 0; i < 5; i++) sor3 = bar(sor1);
|
|
|
|
baz(sor3.value()); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ReturnValue) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor = Make<STATUSOR_INT>();
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, Goto) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
label:
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
goto label;
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
label:
|
|
if (!sor.ok()) goto label;
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (!sor.ok()) return;
|
|
goto label;
|
|
label:
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, JoinDistinctValues) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor;
|
|
if (b)
|
|
sor = Make<STATUSOR_INT>();
|
|
else
|
|
sor = Make<STATUSOR_INT>();
|
|
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor;
|
|
if (b) {
|
|
sor = Make<STATUSOR_INT>();
|
|
if (!sor.ok()) return;
|
|
} else {
|
|
sor = Make<STATUSOR_INT>();
|
|
if (!sor.ok()) return;
|
|
}
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor;
|
|
if (b) {
|
|
sor = Make<STATUSOR_INT>();
|
|
if (!sor.ok()) return;
|
|
} else {
|
|
sor = Make<STATUSOR_INT>();
|
|
}
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, VarDeclInitExprFromPairAccess) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
auto sor = Make<std::pair<int, STATUSOR_INT>>().second;
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
const auto& sor = Make<std::pair<int, STATUSOR_INT>>().second;
|
|
if (sor.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, LValueToRValueCastOfChangingValue) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
bool foo();
|
|
|
|
void target(bool b1) {
|
|
STATUSOR_INT sor;
|
|
if (b1)
|
|
sor = Make<STATUSOR_INT>();
|
|
else
|
|
sor = Make<STATUSOR_INT>();
|
|
|
|
do {
|
|
const auto& b2 = foo();
|
|
if (b2) break;
|
|
|
|
sor.value(); // [[unsafe]]
|
|
} while (true);
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ConstructorInitializer) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
class target {
|
|
target() : foo_(Make<STATUSOR_INT>().value()) { // [[unsafe]]
|
|
}
|
|
int foo_;
|
|
};
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, AssignStatusToBoolVar) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
bool ok = sor.ok();
|
|
if (ok)
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
bool not_ok = !sor.ok();
|
|
if (not_ok)
|
|
sor.value(); // [[unsafe]]
|
|
else
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, StructuredBindings) {
|
|
// Binding to a pair (which is actually a struct in the mock header).
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
const auto [sor, x] = Make<std::pair<STATUSOR_INT, int>>();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
|
|
// Unsafe case.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
const auto [sor, x] = Make<std::pair<STATUSOR_INT, int>>();
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
|
|
// As a reference.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
const auto& [sor, x] = Make<std::pair<STATUSOR_INT, int>>();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
|
|
// Binding to a ref in a struct.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct S {
|
|
STATUSOR_INT& sor;
|
|
int i;
|
|
};
|
|
|
|
void target() {
|
|
const auto& [sor, i] = Make<S>();
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
|
|
// In a loop.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
auto vals = Make<std::vector<std::pair<int, STATUSOR_INT>>>();
|
|
for (const auto& [x, sor] : vals)
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
|
|
// Similar to the above, but InitExpr already has the storage initialized,
|
|
// and bindings refer to them.
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
auto vals = Make<std::vector<std::pair<int, STATUSOR_INT>>>();
|
|
for (const auto& p : vals) {
|
|
const auto& [i, sor] = p;
|
|
if (sor.ok()) sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, AssignCompositeLogicExprToVar) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor, bool b) {
|
|
bool c = sor.ok() && b;
|
|
if (c) sor.value();
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor, bool b) {
|
|
bool c = !(!sor.ok() || !b);
|
|
if (c) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, Subclass) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
class Foo : public STATUSOR_INT {};
|
|
|
|
void target(Foo opt) {
|
|
opt.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, SubclassStatus) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
class Foo : public STATUS {};
|
|
|
|
void target(Foo opt) { opt.ok(); }
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, SubclassOk) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
class Foo : public STATUSOR_INT {};
|
|
|
|
void target(Foo opt) {
|
|
if (opt.ok()) opt.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, SubclassOperator) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
class Foo : public STATUSOR_INT {};
|
|
|
|
void target(Foo opt) {
|
|
*opt; // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, UnwrapValueWithStatusCheck) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.status().ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, UnwrapValueWithStatusRefCheck) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
const STATUS& s = sor.status();
|
|
if (s.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, UnwrapValueWithStatusPtrCheck) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
const STATUS* s = &sor.status();
|
|
if (s->ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, UnwrapValueWithMovedStatus) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (std::move(sor.status()).ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, MembersUsedInsideStatus) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
namespace absl {
|
|
|
|
class Status {
|
|
public:
|
|
bool ok() const;
|
|
|
|
void target() const { ok(); }
|
|
};
|
|
|
|
} // namespace absl
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, StatusUpdate) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
STATUS s;
|
|
s.Update(sor.status());
|
|
if (s.ok())
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
STATUS s;
|
|
s.Update(sor1.status());
|
|
s.Update(sor2.status());
|
|
if (s.ok()) {
|
|
sor1.value();
|
|
sor2.value();
|
|
}
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
STATUS s;
|
|
s.Update(sor1.status());
|
|
CHECK(s.ok());
|
|
s.Update(sor2.status());
|
|
sor1.value();
|
|
sor2.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
STATUS s;
|
|
s.Update(sor1.status());
|
|
CHECK(s.ok());
|
|
sor1.value();
|
|
sor2.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
STATUS s;
|
|
STATUS sor1_status = sor1.status();
|
|
s.Update(std::move(sor1_status));
|
|
CHECK(s.ok());
|
|
sor1.value();
|
|
sor2.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor1, STATUSOR_INT sor2) {
|
|
STATUS s;
|
|
STATUS sor1_status = sor1.status();
|
|
sor1_status.Update(sor2.status());
|
|
s.Update(std::move(sor1_status));
|
|
CHECK(s.ok());
|
|
sor1.value();
|
|
sor2.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
const STATUS& OptStatus();
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
auto s = sor.status();
|
|
s.Update(OptStatus());
|
|
if (s.ok()) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, EqualityCheck) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x == y)
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (y == x)
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x != y)
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (y != x)
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (!(x == y))
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (!(x != y))
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x == y)
|
|
if (x.ok()) y.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status() == y.status())
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status() != y.status())
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)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"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.ok() == y.ok())
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.ok() != y.ok())
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status().ok() == y.status().ok())
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status().ok() != y.status().ok())
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status().ok() == y.ok())
|
|
y.value();
|
|
else
|
|
y.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT x, STATUSOR_INT y) {
|
|
if (x.ok()) {
|
|
if (x.status().ok() != y.ok())
|
|
y.value(); // [[unsafe]]
|
|
else
|
|
y.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b, STATUSOR_INT sor) {
|
|
if (sor.ok() == b) {
|
|
if (b) sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok() == true) sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT sor) {
|
|
if (sor.ok() == false) sor.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor1;
|
|
STATUSOR_INT sor2 = Make<STATUSOR_INT>();
|
|
if (sor1 == sor2) sor2.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor1 = Make<STATUSOR_INT>();
|
|
STATUSOR_INT sor2;
|
|
if (sor1 == sor2) sor1.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, PointerEqualityCheck) {
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT* x, STATUSOR_INT* y) {
|
|
if (x->ok()) {
|
|
if (x == y)
|
|
y->value();
|
|
else
|
|
y->value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUSOR_INT* x, STATUSOR_INT* y) {
|
|
if (x->ok()) {
|
|
if (x != y)
|
|
y->value(); // [[unsafe]]
|
|
else
|
|
y->value();
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUS* x, STATUS* y) {
|
|
auto sor = Make<STATUSOR_INT>();
|
|
if (x->ok()) {
|
|
if (x == y && sor.status() == *y)
|
|
sor.value();
|
|
else
|
|
sor.value(); // [[unsafe]]
|
|
}
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(STATUS* x, STATUS* y) {
|
|
auto sor = Make<STATUSOR_INT>();
|
|
if (x->ok()) {
|
|
if (x != y)
|
|
sor.value(); // [[unsafe]]
|
|
else if (sor.status() == *y)
|
|
sor.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, Emplace) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
Foo(int);
|
|
};
|
|
|
|
void target(absl::StatusOr<Foo> sor, int value) {
|
|
sor.emplace(value);
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
struct Foo {
|
|
Foo(std::initializer_list<int>, int);
|
|
};
|
|
|
|
void target(absl::StatusOr<Foo> sor, int value) {
|
|
sor.emplace({1, 2, 3}, value);
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT sor;
|
|
bool sor_ok = sor.ok();
|
|
if (!sor_ok)
|
|
sor.emplace(42);
|
|
sor.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target(bool b) {
|
|
STATUSOR_INT sor;
|
|
if (b) sor.emplace(42);
|
|
if (b) sor.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ValueConstruction) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result = false;
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result = 21;
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result = Make<STATUSOR_INT>();
|
|
result.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result = false;
|
|
if (result.ok())
|
|
result.value();
|
|
else
|
|
result.value();
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result(false);
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result(21);
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result(Make<STATUSOR_INT>());
|
|
result.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result(false);
|
|
if (result.ok())
|
|
result.value();
|
|
else
|
|
result.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ValueAssignment) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result;
|
|
result = false;
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result;
|
|
result = 21;
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_INT result;
|
|
result = Make<STATUSOR_INT>();
|
|
result.value(); // [[unsafe]]
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(
|
|
R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_BOOL result;
|
|
result = false;
|
|
if (result.ok())
|
|
result.value();
|
|
else
|
|
result.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, NestedStatusOr) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
absl::StatusOr<STATUSOR_INT> result;
|
|
result = Make<STATUSOR_INT>();
|
|
result.value();
|
|
}
|
|
)cc");
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
absl::StatusOr<STATUSOR_INT> result = Make<STATUSOR_INT>();
|
|
result.value();
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, PtrConstruct) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_VOIDPTR sor = nullptr;
|
|
*sor;
|
|
}
|
|
)cc");
|
|
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_VOIDPTR sor(nullptr);
|
|
*sor;
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, InPlaceConstruct) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
STATUSOR_VOIDPTR absl_sor(absl::in_place, {nullptr});
|
|
*absl_sor;
|
|
STATUSOR_VOIDPTR std_sor(std::in_place, {nullptr});
|
|
*std_sor;
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ConstructStatusOrFromReference) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
void target() {
|
|
const auto sor1 = Make<STATUSOR_INT&>();
|
|
const auto sor2 = Make<STATUSOR_INT&>();
|
|
if (!sor1.ok() && !sor2.ok()) return;
|
|
if (sor1.ok() && !sor2.ok()) {
|
|
} else if (!sor1.ok() && sor2.ok()) {
|
|
} else {
|
|
sor1.value();
|
|
sor2.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
TEST_P(UncheckedStatusOrAccessModelTest, ConstructStatusFromReference) {
|
|
ExpectDiagnosticsFor(R"cc(
|
|
#include "unchecked_statusor_access_test_defs.h"
|
|
|
|
void target() {
|
|
const auto sor1 = Make<STATUSOR_INT&>();
|
|
const auto sor2 = Make<STATUSOR_INT&>();
|
|
const auto s1 = Make<STATUS&>();
|
|
const auto s2 = Make<STATUS&>();
|
|
|
|
if (!s1.ok() && !s2.ok()) return;
|
|
if (s1.ok() && !s2.ok()) {
|
|
} else if (!s1.ok() && s2.ok()) {
|
|
} else {
|
|
if (s1 != sor1.status() || s2 != sor2.status()) return;
|
|
sor1.value();
|
|
sor2.value();
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::string
|
|
GetAliasMacros(UncheckedStatusOrAccessModelTestAliasKind AliasKind) {
|
|
switch (AliasKind) {
|
|
case UncheckedStatusOrAccessModelTestAliasKind::kUnaliased:
|
|
return R"cc(
|
|
#define STATUSOR_INT ::absl::StatusOr<int>
|
|
#define STATUSOR_BOOL ::absl::StatusOr<bool>
|
|
#define STATUSOR_VOIDPTR ::absl::StatusOr<void*>
|
|
#define STATUS ::absl::Status
|
|
)cc";
|
|
case UncheckedStatusOrAccessModelTestAliasKind::kPartiallyAliased:
|
|
return R"cc(
|
|
template <typename T>
|
|
using StatusOrAlias = ::absl::StatusOr<T>;
|
|
#define STATUSOR_INT StatusOrAlias<int>
|
|
#define STATUSOR_BOOL StatusOrAlias<bool>
|
|
#define STATUSOR_VOIDPTR StatusOrAlias<void*>
|
|
#define STATUS ::absl::Status
|
|
)cc";
|
|
case UncheckedStatusOrAccessModelTestAliasKind::kFullyAliased:
|
|
return R"cc(
|
|
using StatusOrIntAlias = ::absl::StatusOr<int>;
|
|
#define STATUSOR_INT StatusOrIntAlias
|
|
using StatusOrBoolAlias = ::absl::StatusOr<bool>;
|
|
#define STATUSOR_BOOL StatusOrBoolAlias
|
|
using StatusOrVoidPtrAlias = ::absl::StatusOr<void*>;
|
|
#define STATUSOR_VOIDPTR StatusOrVoidPtrAlias
|
|
using StatusAlias = ::absl::Status;
|
|
#define STATUS StatusAlias
|
|
)cc";
|
|
}
|
|
llvm_unreachable("Unknown alias kind.");
|
|
}
|
|
|
|
std::vector<std::pair<std::string, std::string>>
|
|
GetHeaders(UncheckedStatusOrAccessModelTestAliasKind AliasKind) {
|
|
auto Headers = test::getMockHeaders();
|
|
|
|
Headers.emplace_back("unchecked_statusor_access_test_defs.h",
|
|
R"cc(
|
|
#include "cstddef.h"
|
|
#include "statusor_defs.h"
|
|
#include "std_optional.h"
|
|
#include "std_vector.h"
|
|
#include "std_pair.h"
|
|
#include "absl_log.h"
|
|
#include "testing_defs.h"
|
|
|
|
template <typename T>
|
|
T Make();
|
|
|
|
class Fatal {
|
|
public:
|
|
~Fatal() __attribute__((noreturn));
|
|
int value();
|
|
};
|
|
)cc" +
|
|
GetAliasMacros(AliasKind));
|
|
return Headers;
|
|
}
|
|
} // namespace clang::dataflow::statusor_model
|