1// RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I %S/Inputs/unchecked-optional-access
2
3#include "absl/types/optional.h"
4#include "folly/types/Optional.h"
5
6void unchecked_value_access(const absl::optional<int> &opt) {
7 opt.value();
8 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
9}
10
11void unchecked_deref_operator_access(const absl::optional<int> &opt) {
12 *opt;
13 // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value
14}
15
16struct Foo {
17 void foo() const {}
18};
19
20void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
21 opt->foo();
22 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
23}
24
25void folly_check_value_then_reset(folly::Optional<int> opt) {
26 if (opt) {
27 opt.reset();
28 opt.value();
29 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
30 }
31}
32
33void folly_value_after_swap(folly::Optional<int> opt1, folly::Optional<int> opt2) {
34 if (opt1) {
35 opt1.swap(opt2);
36 opt1.value();
37 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
38 }
39}
40
41void checked_access(const absl::optional<int> &opt) {
42 if (opt.has_value()) {
43 opt.value();
44 }
45}
46
47void folly_checked_access(const folly::Optional<int> &opt) {
48 if (opt.hasValue()) {
49 opt.value();
50 }
51}
52
53template <typename T>
54void function_template_without_user(const absl::optional<T> &opt) {
55 opt.value(); // no-warning
56}
57
58template <typename T>
59void function_template_with_user(const absl::optional<T> &opt) {
60 opt.value();
61 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
62}
63
64void function_template_user(const absl::optional<int> &opt) {
65 // Instantiate the f3 function template so that it gets matched by the check.
66 function_template_with_user(opt);
67}
68
69template <typename T>
70void function_template_with_specialization(const absl::optional<int> &opt) {
71 opt.value(); // no-warning
72}
73
74template <>
75void function_template_with_specialization<int>(
76 const absl::optional<int> &opt) {
77 opt.value();
78 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
79}
80
81template <typename T>
82class ClassTemplateWithSpecializations {
83 void f(const absl::optional<int> &opt) {
84 opt.value(); // no-warning
85 }
86};
87
88template <typename T>
89class ClassTemplateWithSpecializations<T *> {
90 void f(const absl::optional<int> &opt) {
91 opt.value(); // no-warning
92 }
93};
94
95template <>
96class ClassTemplateWithSpecializations<int> {
97 void f(const absl::optional<int> &opt) {
98 opt.value();
99 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
100 }
101};
102
103// The templates below are not instantiated and CFGs can not be properly built
104// for them. They are here to make sure that the checker does not crash, but
105// instead ignores non-instantiated templates.
106
107template <typename T>
108struct C1 {};
109
110template <typename T>
111struct C2 : public C1<T> {
112 ~C2() {}
113};
114
115template <typename T, template <class> class B>
116struct C3 : public B<T> {
117 ~C3() {}
118};
119
120void multiple_unchecked_accesses(absl::optional<int> opt1,
121 absl::optional<int> opt2) {
122 for (int i = 0; i < 10; i++) {
123 opt1.value();
124 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
125 }
126 opt2.value();
127 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
128}
129
130class C4 {
131 explicit C4(absl::optional<int> opt) : foo_(opt.value()) {
132 // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: unchecked access to optional
133 }
134 int foo_;
135};
136
137// llvm#59705
138namespace std
139{
140 template <typename T>
141 constexpr T&& forward(T& type) noexcept {
142 return static_cast<T&&>(type);
143 }
144
145 template <typename T>
146 constexpr T&& forward(T&& type) noexcept {
147 return static_cast<T&&>(type);
148 }
149}
150
151void std_forward_copy(absl::optional<int> opt) {
152 std::forward<absl::optional<int>>(opt).value();
153 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
154}
155
156void std_forward_copy_safe(absl::optional<int> opt) {
157 if (!opt) return;
158
159 std::forward<absl::optional<int>>(opt).value();
160}
161
162void std_forward_copy(absl::optional<int>& opt) {
163 std::forward<absl::optional<int>>(opt).value();
164 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
165}
166
167void std_forward_lvalue_ref_safe(absl::optional<int>& opt) {
168 if (!opt) return;
169
170 std::forward<absl::optional<int>>(opt).value();
171}
172
173void std_forward_copy(absl::optional<int>&& opt) {
174 std::forward<absl::optional<int>>(opt).value();
175 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
176}
177
178void std_forward_rvalue_ref_safe(absl::optional<int>&& opt) {
179 if (!opt) return;
180
181 std::forward<absl::optional<int>>(opt).value();
182}
183
184namespace std {
185
186template <typename T> class vector {
187public:
188 T &operator[](unsigned long index);
189 bool empty();
190};
191
192} // namespace std
193
194struct S {
195 absl::optional<float> x;
196};
197std::vector<S> vec;
198
199void foo() {
200 if (!vec.empty())
201 vec[0].x = 0;
202}
203

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp