blob: 724fe021f31bd7ea9a325c11b0d666bffc1d96f8 [file]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Tests for comparisons of types containing nullability annotations.
#include "nullability_verification/test/check_diagnostics.h"
#include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h"
namespace clang {
namespace tidy {
namespace nullability {
namespace {
TEST(PointerNullabilityTest, CompareNonNullPtrAndNonNullPtr) {
// nonnull == nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x, int* _Nonnull y) {
*x;
*y;
if (x == y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
// nonnull != nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x, int* _Nonnull y) {
*x;
*y;
if (x != y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
}
TEST(PointerNullabilityTest, CompareNullablePtrAndNullablePtr) {
// nullable == nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nullable y) {
*x; // [[unsafe]]
*y; // [[unsafe]]
if (x == y) {
*x; // [[unsafe]]
*y; // [[unsafe]]
} else {
*x; // [[unsafe]]
*y; // [[unsafe]]
}
*x; // [[unsafe]]
*y; // [[unsafe]]
}
)cc"));
// nullable != nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nullable y) {
*x; // [[unsafe]]
*y; // [[unsafe]]
if (x != y) {
*x; // [[unsafe]]
*y; // [[unsafe]]
} else {
*x; // [[unsafe]]
*y; // [[unsafe]]
}
*x; // [[unsafe]]
*y; // [[unsafe]]
}
)cc"));
}
TEST(PointerNullabilityTest, CompareUnknownPtrAndUnknownPtr) {
// unknown == unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *y) {
*x;
*y;
if (x == y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
// unknown != unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *y) {
*x;
*y;
if (x != y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
}
// TODO(b/233582219): Implement diagnosis of unreachable program points
TEST(PointerNullabilityTest, CompareNonNullPtrAndNullPtr) {
// nonnull == nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x) {
*x;
if (x == nullptr) {
*x; // unreachable
} else {
*x;
}
*x;
}
)cc"));
// nullptr == nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x) {
*x;
if (nullptr == x) {
*x; // unreachable
} else {
*x;
}
*x;
}
)cc"));
// nonnull != nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x) {
*x;
if (x != nullptr) {
*x;
} else {
*x; // unreachable
}
*x;
}
)cc"));
// nullptr != nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nonnull x) {
*x;
if (nullptr != x) {
*x;
} else {
*x; // unreachable
}
*x;
}
)cc"));
}
TEST(PointerNullabilityTest, CompareNullablePtrAndNullPtr) {
// nullable == nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x) {
*x; // [[unsafe]]
if (x == nullptr) {
*x; // [[unsafe]]
} else {
*x;
}
*x; // [[unsafe]]
}
)cc"));
// nullptr == nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x) {
*x; // [[unsafe]]
if (nullptr == x) {
*x; // [[unsafe]]
} else {
*x;
}
*x; // [[unsafe]]
}
)cc"));
// nullable != nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x) {
*x; // [[unsafe]]
if (x != nullptr) {
*x;
} else {
*x; // [[unsafe]]
}
*x; // [[unsafe]]
}
)cc"));
// nullptr != nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x) {
*x; // [[unsafe]]
if (nullptr != x) {
*x;
} else {
*x; // [[unsafe]]
}
*x; // [[unsafe]]
}
)cc"));
}
TEST(PointerNullabilityTest, CompareNullablePtrAndNonNullPtr) {
// nullable == nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nonnull y) {
*x; // [[unsafe]]
*y;
if (x == y) {
*x;
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// nonnull == nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nonnull y) {
*x; // [[unsafe]]
*y;
if (y == x) {
*x;
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// nullable != nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nonnull y) {
*x; // [[unsafe]]
*y;
if (x != y) {
*x; // [[unsafe]]
*y;
} else {
*x;
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// nonnull != nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int* _Nullable x, int* _Nonnull y) {
*x; // [[unsafe]]
*y;
if (y != x) {
*x; // [[unsafe]]
*y;
} else {
*x;
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
}
TEST(PointerNullabilityTest, CompareNullablePtrAndUnknownPtr) {
// nullable == unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *_Nullable x, int *y) {
*x; // [[unsafe]]
*y;
if (x == y) {
*x; // [[unsafe]]
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// unknown == nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *_Nullable x, int *y) {
*x; // [[unsafe]]
*y;
if (y == x) {
*x; // [[unsafe]]
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// nullable != unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *_Nullable x, int *y) {
*x; // [[unsafe]]
*y;
if (x != y) {
*x; // [[unsafe]]
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
// unknown != nullable
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *_Nullable x, int *y) {
*x; // [[unsafe]]
*y;
if (y != x) {
*x; // [[unsafe]]
*y;
} else {
*x; // [[unsafe]]
*y;
}
*x; // [[unsafe]]
*y;
}
)cc"));
}
// TODO(b/233582219): Fix false negatives. The pointer is compared to nullptr,
// hence the unnannotated pointer should be considered nullable and emit
// warnings where it fails or is not null checked.
TEST(PointerNullabilityTest, CompareUnknownPtrAndNullPtr) {
// unknown == nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x) {
*x; // false-negative
if (x == nullptr) {
*x; // false-negative
} else {
*x;
}
*x; // false-negative
}
)cc"));
// nullptr == unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x) {
*x; // false-negative
if (nullptr == x) {
*x; // false-negative
} else {
*x;
}
*x; // false-negative
}
)cc"));
// unknown != nullptr
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x) {
*x; // false-negative
if (x != nullptr) {
*x;
} else {
*x; // false-negative
}
*x; // false-negative
}
)cc"));
// nullptr != unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x) {
*x; // false-negative
if (nullptr != x) {
*x;
} else {
*x; // false-negative
}
*x; // false-negative
}
)cc"));
}
TEST(PointerNullabilityTest, CompareUnknownPtrAndNonNullPtr) {
// unknown == nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *_Nonnull y) {
*x;
*y;
if (x == y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
// nonnull == unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *_Nonnull y) {
*x;
*y;
if (y == x) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
// unknown != nonnull
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *_Nonnull y) {
*x;
*y;
if (x != y) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
// nonnull != unknown
EXPECT_TRUE(checkDiagnostics(R"cc(
void target(int *x, int *_Nonnull y) {
*x;
*y;
if (y != x) {
*x;
*y;
} else {
*x;
*y;
}
*x;
*y;
}
)cc"));
}
} // namespace
} // namespace nullability
} // namespace tidy
} // namespace clang