1 // Copyright 2023 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/base/nullability.h"
16
17 #include <cassert>
18 #include <memory>
19 #include <utility>
20
21 #include "gtest/gtest.h"
22 #include "absl/base/attributes.h"
23
24 namespace {
25 using ::absl::Nonnull;
26 using ::absl::NullabilityUnknown;
27 using ::absl::Nullable;
28
funcWithNonnullArg(Nonnull<int * >)29 void funcWithNonnullArg(Nonnull<int*> /*arg*/) {}
30 template <typename T>
funcWithDeducedNonnullArg(Nonnull<T * >)31 void funcWithDeducedNonnullArg(Nonnull<T*> /*arg*/) {}
32
TEST(NonnullTest,NonnullArgument)33 TEST(NonnullTest, NonnullArgument) {
34 int var = 0;
35 funcWithNonnullArg(&var);
36 funcWithDeducedNonnullArg(&var);
37 }
38
funcWithNonnullReturn()39 Nonnull<int*> funcWithNonnullReturn() {
40 static int var = 0;
41 return &var;
42 }
43
TEST(NonnullTest,NonnullReturn)44 TEST(NonnullTest, NonnullReturn) {
45 auto var = funcWithNonnullReturn();
46 (void)var;
47 }
48
TEST(PassThroughTest,PassesThroughRawPointerToInt)49 TEST(PassThroughTest, PassesThroughRawPointerToInt) {
50 EXPECT_TRUE((std::is_same<Nonnull<int*>, int*>::value));
51 EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
52 EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
53 }
54
TEST(PassThroughTest,PassesThroughRawPointerToVoid)55 TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
56 EXPECT_TRUE((std::is_same<Nonnull<void*>, void*>::value));
57 EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
58 EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
59 }
60
TEST(PassThroughTest,PassesThroughUniquePointerToInt)61 TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
62 using T = std::unique_ptr<int>;
63 EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
64 EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
65 EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
66 }
67
TEST(PassThroughTest,PassesThroughSharedPointerToInt)68 TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
69 using T = std::shared_ptr<int>;
70 EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
71 EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
72 EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
73 }
74
TEST(PassThroughTest,PassesThroughSharedPointerToVoid)75 TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
76 using T = std::shared_ptr<void>;
77 EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
78 EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
79 EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
80 }
81
TEST(PassThroughTest,PassesThroughPointerToMemberObject)82 TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
83 using T = decltype(&std::pair<int, int>::first);
84 EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
85 EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
86 EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
87 }
88
TEST(PassThroughTest,PassesThroughPointerToMemberFunction)89 TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
90 using T = decltype(&std::unique_ptr<int>::reset);
91 EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
92 EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
93 EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
94 }
95
96 } // namespace
97
98 // Nullable ADL lookup test
99 namespace util {
100 // Helper for NullableAdlTest. Returns true, denoting that argument-dependent
101 // lookup found this implementation of DidAdlWin. Must be in namespace
102 // util itself, not a nested anonymous namespace.
103 template <typename T>
DidAdlWin(T *)104 bool DidAdlWin(T*) {
105 return true;
106 }
107
108 // Because this type is defined in namespace util, an unqualified call to
109 // DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
110 struct MakeAdlWin {};
111 } // namespace util
112
113 namespace {
114 // Returns false, denoting that ADL did not inspect namespace util. If it
115 // had, the better match (T*) above would have won out over the (...) here.
DidAdlWin(...)116 bool DidAdlWin(...) { return false; }
117
TEST(NullableAdlTest,NullableAddsNothingToArgumentDependentLookup)118 TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
119 // Treatment: util::Nullable<int*> contributes nothing to ADL because
120 // int* itself doesn't.
121 EXPECT_FALSE(DidAdlWin((int*)nullptr));
122 EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
123
124 // Control: Argument-dependent lookup does find the implementation in
125 // namespace util when the underlying pointee type resides there.
126 EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
127 EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
128 }
129 } // namespace
130