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 #include "bde/types/bsl_optional.h" 6 #include "bde/types/bdlb_nullablevalue.h" 7 8 void unchecked_value_access(const absl::optional<int> &opt) { 9 opt.value(); 10 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 11 } 12 13 void unchecked_deref_operator_access(const absl::optional<int> &opt) { 14 *opt; 15 // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value 16 } 17 18 struct Foo { 19 void foo() const {} 20 }; 21 22 void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) { 23 opt->foo(); 24 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value 25 } 26 27 void folly_check_value_then_reset(folly::Optional<int> opt) { 28 if (opt) { 29 opt.reset(); 30 opt.value(); 31 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value 32 } 33 } 34 35 void folly_value_after_swap(folly::Optional<int> opt1, folly::Optional<int> opt2) { 36 if (opt1) { 37 opt1.swap(opt2); 38 opt1.value(); 39 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value 40 } 41 } 42 43 void checked_access(const absl::optional<int> &opt) { 44 if (opt.has_value()) { 45 opt.value(); 46 } 47 } 48 49 void folly_checked_access(const folly::Optional<int> &opt) { 50 if (opt.hasValue()) { 51 opt.value(); 52 } 53 } 54 55 void bsl_optional_unchecked_value_access(const bsl::optional<int> &opt) { 56 opt.value(); 57 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 58 59 int x = *opt; 60 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 61 62 if (!opt) { 63 return; 64 } 65 66 opt.value(); 67 x = *opt; 68 } 69 70 void bsl_optional_checked_access(const bsl::optional<int> &opt) { 71 if (opt.has_value()) { 72 opt.value(); 73 } 74 if (opt) { 75 opt.value(); 76 } 77 } 78 79 void bsl_optional_value_after_swap(bsl::optional<int> &opt1, bsl::optional<int> &opt2) { 80 if (opt1) { 81 opt1.swap(opt2); 82 opt1.value(); 83 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value 84 } 85 } 86 87 void nullable_value_unchecked_value_access(const BloombergLP::bdlb::NullableValue<int> &opt) { 88 opt.value(); 89 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 90 91 int x = *opt; 92 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 93 94 if (opt.isNull()) { 95 opt.value(); 96 } 97 // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 98 99 if (!opt) { 100 opt.value(); 101 } 102 // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 103 104 if (!opt) { 105 return; 106 } 107 108 opt.value(); 109 x = *opt; 110 } 111 112 void nullable_value_optional_checked_access(const BloombergLP::bdlb::NullableValue<int> &opt) { 113 if (opt.has_value()) { 114 opt.value(); 115 } 116 if (opt) { 117 opt.value(); 118 } 119 if (!opt.isNull()) { 120 opt.value(); 121 } 122 } 123 124 void nullable_value_emplaced(BloombergLP::bdlb::NullableValue<int> &opt) { 125 opt.value(); 126 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 127 128 opt.emplace(1); 129 opt.value(); 130 131 opt.reset(); 132 opt.value(); 133 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access] 134 } 135 136 void nullable_value_after_swap(BloombergLP::bdlb::NullableValue<int> &opt1, BloombergLP::bdlb::NullableValue<int> &opt2) { 137 if (opt1) { 138 opt1.swap(opt2); 139 opt1.value(); 140 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value 141 } 142 } 143 144 template <typename T> 145 void function_template_without_user(const absl::optional<T> &opt) { 146 opt.value(); // no-warning 147 } 148 149 template <typename T> 150 void function_template_with_user(const absl::optional<T> &opt) { 151 opt.value(); 152 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value 153 } 154 155 void function_template_user(const absl::optional<int> &opt) { 156 // Instantiate the f3 function template so that it gets matched by the check. 157 function_template_with_user(opt); 158 } 159 160 template <typename T> 161 void function_template_with_specialization(const absl::optional<int> &opt) { 162 opt.value(); // no-warning 163 } 164 165 template <> 166 void function_template_with_specialization<int>( 167 const absl::optional<int> &opt) { 168 opt.value(); 169 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value 170 } 171 172 template <typename T> 173 class ClassTemplateWithSpecializations { 174 void f(const absl::optional<int> &opt) { 175 opt.value(); // no-warning 176 } 177 }; 178 179 template <typename T> 180 class ClassTemplateWithSpecializations<T *> { 181 void f(const absl::optional<int> &opt) { 182 opt.value(); // no-warning 183 } 184 }; 185 186 template <> 187 class ClassTemplateWithSpecializations<int> { 188 void f(const absl::optional<int> &opt) { 189 opt.value(); 190 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional 191 } 192 }; 193 194 // The templates below are not instantiated and CFGs can not be properly built 195 // for them. They are here to make sure that the checker does not crash, but 196 // instead ignores non-instantiated templates. 197 198 template <typename T> 199 struct C1 {}; 200 201 template <typename T> 202 struct C2 : public C1<T> { 203 ~C2() {} 204 }; 205 206 template <typename T, template <class> class B> 207 struct C3 : public B<T> { 208 ~C3() {} 209 }; 210 211 void multiple_unchecked_accesses(absl::optional<int> opt1, 212 absl::optional<int> opt2) { 213 for (int i = 0; i < 10; i++) { 214 opt1.value(); 215 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional 216 } 217 opt2.value(); 218 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value 219 } 220 221 class C4 { 222 explicit C4(absl::optional<int> opt) : foo_(opt.value()) { 223 // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: unchecked access to optional 224 } 225 int foo_; 226 }; 227 228 // llvm#59705 229 namespace std 230 { 231 template <typename T> 232 constexpr T&& forward(T& type) noexcept { 233 return static_cast<T&&>(type); 234 } 235 236 template <typename T> 237 constexpr T&& forward(T&& type) noexcept { 238 return static_cast<T&&>(type); 239 } 240 } 241 242 void std_forward_copy(absl::optional<int> opt) { 243 std::forward<absl::optional<int>>(opt).value(); 244 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 245 } 246 247 void std_forward_copy_safe(absl::optional<int> opt) { 248 if (!opt) return; 249 250 std::forward<absl::optional<int>>(opt).value(); 251 } 252 253 void std_forward_copy(absl::optional<int>& opt) { 254 std::forward<absl::optional<int>>(opt).value(); 255 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 256 } 257 258 void std_forward_lvalue_ref_safe(absl::optional<int>& opt) { 259 if (!opt) return; 260 261 std::forward<absl::optional<int>>(opt).value(); 262 } 263 264 void std_forward_copy(absl::optional<int>&& opt) { 265 std::forward<absl::optional<int>>(opt).value(); 266 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 267 } 268 269 void std_forward_rvalue_ref_safe(absl::optional<int>&& opt) { 270 if (!opt) return; 271 272 std::forward<absl::optional<int>>(opt).value(); 273 } 274 275 namespace std { 276 277 template <typename T> class vector { 278 public: 279 T &operator[](unsigned long index); 280 bool empty(); 281 }; 282 283 } // namespace std 284 285 struct S { 286 absl::optional<float> x; 287 }; 288 std::vector<S> vec; 289 290 void foo() { 291 if (!vec.empty()) 292 vec[0].x = 0; 293 } 294