xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp (revision 11c423f9bebc3be27722225ca8120e8775be836c)
189a1d03eSRichard // RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I %S/Inputs/unchecked-optional-access
289a1d03eSRichard 
389a1d03eSRichard #include "absl/types/optional.h"
42f0630f8SAnton Dukeman #include "folly/types/Optional.h"
5*11c423f9SChris Cotter #include "bde/types/bsl_optional.h"
6*11c423f9SChris Cotter #include "bde/types/bdlb_nullablevalue.h"
789a1d03eSRichard 
889a1d03eSRichard void unchecked_value_access(const absl::optional<int> &opt) {
989a1d03eSRichard   opt.value();
1089a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
1189a1d03eSRichard }
1289a1d03eSRichard 
1389a1d03eSRichard void unchecked_deref_operator_access(const absl::optional<int> &opt) {
1489a1d03eSRichard   *opt;
1589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value
1689a1d03eSRichard }
1789a1d03eSRichard 
1889a1d03eSRichard struct Foo {
1989a1d03eSRichard   void foo() const {}
2089a1d03eSRichard };
2189a1d03eSRichard 
2289a1d03eSRichard void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
2389a1d03eSRichard   opt->foo();
2489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
2589a1d03eSRichard }
2689a1d03eSRichard 
272f0630f8SAnton Dukeman void folly_check_value_then_reset(folly::Optional<int> opt) {
282f0630f8SAnton Dukeman   if (opt) {
292f0630f8SAnton Dukeman     opt.reset();
302f0630f8SAnton Dukeman     opt.value();
312f0630f8SAnton Dukeman     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
322f0630f8SAnton Dukeman   }
332f0630f8SAnton Dukeman }
342f0630f8SAnton Dukeman 
352f0630f8SAnton Dukeman void folly_value_after_swap(folly::Optional<int> opt1, folly::Optional<int> opt2) {
362f0630f8SAnton Dukeman   if (opt1) {
372f0630f8SAnton Dukeman     opt1.swap(opt2);
382f0630f8SAnton Dukeman     opt1.value();
392f0630f8SAnton Dukeman     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
402f0630f8SAnton Dukeman   }
412f0630f8SAnton Dukeman }
422f0630f8SAnton Dukeman 
4389a1d03eSRichard void checked_access(const absl::optional<int> &opt) {
4489a1d03eSRichard   if (opt.has_value()) {
4589a1d03eSRichard     opt.value();
4689a1d03eSRichard   }
4789a1d03eSRichard }
4889a1d03eSRichard 
492f0630f8SAnton Dukeman void folly_checked_access(const folly::Optional<int> &opt) {
502f0630f8SAnton Dukeman   if (opt.hasValue()) {
512f0630f8SAnton Dukeman     opt.value();
522f0630f8SAnton Dukeman   }
532f0630f8SAnton Dukeman }
542f0630f8SAnton Dukeman 
55*11c423f9SChris Cotter void bsl_optional_unchecked_value_access(const bsl::optional<int> &opt) {
56*11c423f9SChris Cotter   opt.value();
57*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
58*11c423f9SChris Cotter 
59*11c423f9SChris Cotter   int x = *opt;
60*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
61*11c423f9SChris Cotter 
62*11c423f9SChris Cotter   if (!opt) {
63*11c423f9SChris Cotter     return;
64*11c423f9SChris Cotter   }
65*11c423f9SChris Cotter 
66*11c423f9SChris Cotter   opt.value();
67*11c423f9SChris Cotter   x = *opt;
68*11c423f9SChris Cotter }
69*11c423f9SChris Cotter 
70*11c423f9SChris Cotter void bsl_optional_checked_access(const bsl::optional<int> &opt) {
71*11c423f9SChris Cotter   if (opt.has_value()) {
72*11c423f9SChris Cotter     opt.value();
73*11c423f9SChris Cotter   }
74*11c423f9SChris Cotter   if (opt) {
75*11c423f9SChris Cotter     opt.value();
76*11c423f9SChris Cotter   }
77*11c423f9SChris Cotter }
78*11c423f9SChris Cotter 
79*11c423f9SChris Cotter void bsl_optional_value_after_swap(bsl::optional<int> &opt1, bsl::optional<int> &opt2) {
80*11c423f9SChris Cotter   if (opt1) {
81*11c423f9SChris Cotter     opt1.swap(opt2);
82*11c423f9SChris Cotter     opt1.value();
83*11c423f9SChris Cotter     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
84*11c423f9SChris Cotter   }
85*11c423f9SChris Cotter }
86*11c423f9SChris Cotter 
87*11c423f9SChris Cotter void nullable_value_unchecked_value_access(const BloombergLP::bdlb::NullableValue<int> &opt) {
88*11c423f9SChris Cotter   opt.value();
89*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
90*11c423f9SChris Cotter 
91*11c423f9SChris Cotter   int x = *opt;
92*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
93*11c423f9SChris Cotter 
94*11c423f9SChris Cotter   if (opt.isNull()) {
95*11c423f9SChris Cotter     opt.value();
96*11c423f9SChris Cotter   }
97*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
98*11c423f9SChris Cotter 
99*11c423f9SChris Cotter   if (!opt) {
100*11c423f9SChris Cotter     opt.value();
101*11c423f9SChris Cotter   }
102*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
103*11c423f9SChris Cotter 
104*11c423f9SChris Cotter   if (!opt) {
105*11c423f9SChris Cotter     return;
106*11c423f9SChris Cotter   }
107*11c423f9SChris Cotter 
108*11c423f9SChris Cotter   opt.value();
109*11c423f9SChris Cotter   x = *opt;
110*11c423f9SChris Cotter }
111*11c423f9SChris Cotter 
112*11c423f9SChris Cotter void nullable_value_optional_checked_access(const BloombergLP::bdlb::NullableValue<int> &opt) {
113*11c423f9SChris Cotter   if (opt.has_value()) {
114*11c423f9SChris Cotter     opt.value();
115*11c423f9SChris Cotter   }
116*11c423f9SChris Cotter   if (opt) {
117*11c423f9SChris Cotter     opt.value();
118*11c423f9SChris Cotter   }
119*11c423f9SChris Cotter   if (!opt.isNull()) {
120*11c423f9SChris Cotter     opt.value();
121*11c423f9SChris Cotter   }
122*11c423f9SChris Cotter }
123*11c423f9SChris Cotter 
124*11c423f9SChris Cotter void nullable_value_emplaced(BloombergLP::bdlb::NullableValue<int> &opt) {
125*11c423f9SChris Cotter   opt.value();
126*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
127*11c423f9SChris Cotter 
128*11c423f9SChris Cotter   opt.emplace(1);
129*11c423f9SChris Cotter   opt.value();
130*11c423f9SChris Cotter 
131*11c423f9SChris Cotter   opt.reset();
132*11c423f9SChris Cotter   opt.value();
133*11c423f9SChris Cotter   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
134*11c423f9SChris Cotter }
135*11c423f9SChris Cotter 
136*11c423f9SChris Cotter void nullable_value_after_swap(BloombergLP::bdlb::NullableValue<int> &opt1, BloombergLP::bdlb::NullableValue<int> &opt2) {
137*11c423f9SChris Cotter   if (opt1) {
138*11c423f9SChris Cotter     opt1.swap(opt2);
139*11c423f9SChris Cotter     opt1.value();
140*11c423f9SChris Cotter     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
141*11c423f9SChris Cotter   }
142*11c423f9SChris Cotter }
143*11c423f9SChris Cotter 
14489a1d03eSRichard template <typename T>
14589a1d03eSRichard void function_template_without_user(const absl::optional<T> &opt) {
14689a1d03eSRichard   opt.value(); // no-warning
14789a1d03eSRichard }
14889a1d03eSRichard 
14989a1d03eSRichard template <typename T>
15089a1d03eSRichard void function_template_with_user(const absl::optional<T> &opt) {
15189a1d03eSRichard   opt.value();
15289a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
15389a1d03eSRichard }
15489a1d03eSRichard 
15589a1d03eSRichard void function_template_user(const absl::optional<int> &opt) {
15689a1d03eSRichard   // Instantiate the f3 function template so that it gets matched by the check.
15789a1d03eSRichard   function_template_with_user(opt);
15889a1d03eSRichard }
15989a1d03eSRichard 
16089a1d03eSRichard template <typename T>
16189a1d03eSRichard void function_template_with_specialization(const absl::optional<int> &opt) {
16289a1d03eSRichard   opt.value(); // no-warning
16389a1d03eSRichard }
16489a1d03eSRichard 
16589a1d03eSRichard template <>
16689a1d03eSRichard void function_template_with_specialization<int>(
16789a1d03eSRichard     const absl::optional<int> &opt) {
16889a1d03eSRichard   opt.value();
16989a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
17089a1d03eSRichard }
17189a1d03eSRichard 
17289a1d03eSRichard template <typename T>
17389a1d03eSRichard class ClassTemplateWithSpecializations {
17489a1d03eSRichard   void f(const absl::optional<int> &opt) {
17589a1d03eSRichard     opt.value(); // no-warning
17689a1d03eSRichard   }
17789a1d03eSRichard };
17889a1d03eSRichard 
17989a1d03eSRichard template <typename T>
18089a1d03eSRichard class ClassTemplateWithSpecializations<T *> {
18189a1d03eSRichard   void f(const absl::optional<int> &opt) {
18289a1d03eSRichard     opt.value(); // no-warning
18389a1d03eSRichard   }
18489a1d03eSRichard };
18589a1d03eSRichard 
18689a1d03eSRichard template <>
18789a1d03eSRichard class ClassTemplateWithSpecializations<int> {
18889a1d03eSRichard   void f(const absl::optional<int> &opt) {
18989a1d03eSRichard     opt.value();
19089a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
19189a1d03eSRichard   }
19289a1d03eSRichard };
19389a1d03eSRichard 
19489a1d03eSRichard // The templates below are not instantiated and CFGs can not be properly built
19589a1d03eSRichard // for them. They are here to make sure that the checker does not crash, but
19689a1d03eSRichard // instead ignores non-instantiated templates.
19789a1d03eSRichard 
19889a1d03eSRichard template <typename T>
19989a1d03eSRichard struct C1 {};
20089a1d03eSRichard 
20189a1d03eSRichard template <typename T>
20289a1d03eSRichard struct C2 : public C1<T> {
20389a1d03eSRichard   ~C2() {}
20489a1d03eSRichard };
20589a1d03eSRichard 
20689a1d03eSRichard template <typename T, template <class> class B>
20789a1d03eSRichard struct C3 : public B<T> {
20889a1d03eSRichard   ~C3() {}
20989a1d03eSRichard };
21089a1d03eSRichard 
21189a1d03eSRichard void multiple_unchecked_accesses(absl::optional<int> opt1,
21289a1d03eSRichard                                  absl::optional<int> opt2) {
21389a1d03eSRichard   for (int i = 0; i < 10; i++) {
21489a1d03eSRichard     opt1.value();
21589a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
21689a1d03eSRichard   }
21789a1d03eSRichard   opt2.value();
21889a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
21989a1d03eSRichard }
22089a1d03eSRichard 
22189a1d03eSRichard class C4 {
22289a1d03eSRichard   explicit C4(absl::optional<int> opt) : foo_(opt.value()) {
22389a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: unchecked access to optional
22489a1d03eSRichard   }
22589a1d03eSRichard   int foo_;
22689a1d03eSRichard };
22725956d55SAMS21 
22825956d55SAMS21 // llvm#59705
22925956d55SAMS21 namespace std
23025956d55SAMS21 {
23125956d55SAMS21   template <typename T>
23225956d55SAMS21   constexpr T&& forward(T& type) noexcept {
23325956d55SAMS21     return static_cast<T&&>(type);
23425956d55SAMS21   }
23525956d55SAMS21 
23625956d55SAMS21   template <typename T>
23725956d55SAMS21   constexpr T&& forward(T&& type) noexcept {
23825956d55SAMS21     return static_cast<T&&>(type);
23925956d55SAMS21   }
24025956d55SAMS21 }
24125956d55SAMS21 
24225956d55SAMS21 void std_forward_copy(absl::optional<int> opt) {
24325956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
24425956d55SAMS21   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
24525956d55SAMS21 }
24625956d55SAMS21 
24725956d55SAMS21 void std_forward_copy_safe(absl::optional<int> opt) {
24825956d55SAMS21   if (!opt) return;
24925956d55SAMS21 
25025956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
25125956d55SAMS21 }
25225956d55SAMS21 
25325956d55SAMS21 void std_forward_copy(absl::optional<int>& opt) {
25425956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
25525956d55SAMS21   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
25625956d55SAMS21 }
25725956d55SAMS21 
25825956d55SAMS21 void std_forward_lvalue_ref_safe(absl::optional<int>& opt) {
25925956d55SAMS21   if (!opt) return;
26025956d55SAMS21 
26125956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
26225956d55SAMS21 }
26325956d55SAMS21 
26425956d55SAMS21 void std_forward_copy(absl::optional<int>&& opt) {
26525956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
26625956d55SAMS21   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
26725956d55SAMS21 }
26825956d55SAMS21 
26925956d55SAMS21 void std_forward_rvalue_ref_safe(absl::optional<int>&& opt) {
27025956d55SAMS21   if (!opt) return;
27125956d55SAMS21 
27225956d55SAMS21   std::forward<absl::optional<int>>(opt).value();
27325956d55SAMS21 }
27414bc11a6SQizhi Hu 
27514bc11a6SQizhi Hu namespace std {
27614bc11a6SQizhi Hu 
27714bc11a6SQizhi Hu template <typename T> class vector {
27814bc11a6SQizhi Hu public:
27914bc11a6SQizhi Hu   T &operator[](unsigned long index);
28014bc11a6SQizhi Hu   bool empty();
28114bc11a6SQizhi Hu };
28214bc11a6SQizhi Hu 
28314bc11a6SQizhi Hu } // namespace std
28414bc11a6SQizhi Hu 
28514bc11a6SQizhi Hu struct S {
28614bc11a6SQizhi Hu   absl::optional<float> x;
28714bc11a6SQizhi Hu };
28814bc11a6SQizhi Hu std::vector<S> vec;
28914bc11a6SQizhi Hu 
29014bc11a6SQizhi Hu void foo() {
29114bc11a6SQizhi Hu   if (!vec.empty())
29214bc11a6SQizhi Hu     vec[0].x = 0;
29314bc11a6SQizhi Hu }
294