| 1 | // RUN: %check_clang_tidy %s readability-redundant-smartptr-get %t |
| 2 | |
| 3 | #define NULL __null |
| 4 | |
| 5 | namespace std { |
| 6 | |
| 7 | template <typename T> |
| 8 | struct unique_ptr { |
| 9 | T& operator*() const; |
| 10 | T* operator->() const; |
| 11 | T* get() const; |
| 12 | explicit operator bool() const noexcept; |
| 13 | }; |
| 14 | |
| 15 | template <typename T> |
| 16 | struct unique_ptr<T[]> { |
| 17 | T& operator[](unsigned) const; |
| 18 | T* get() const; |
| 19 | explicit operator bool() const noexcept; |
| 20 | }; |
| 21 | |
| 22 | template <typename T> |
| 23 | struct shared_ptr { |
| 24 | T& operator*() const; |
| 25 | T* operator->() const; |
| 26 | T* get() const; |
| 27 | explicit operator bool() const noexcept; |
| 28 | }; |
| 29 | |
| 30 | template <typename T> |
| 31 | struct shared_ptr<T[]> { |
| 32 | T& operator[](unsigned) const; |
| 33 | T* get() const; |
| 34 | explicit operator bool() const noexcept; |
| 35 | }; |
| 36 | |
| 37 | template <typename T> |
| 38 | struct vector { |
| 39 | vector(); |
| 40 | bool operator==(const vector<T>& other) const; |
| 41 | bool operator!=(const vector<T>& other) const; |
| 42 | unsigned long size() const; |
| 43 | bool empty() const; |
| 44 | |
| 45 | using iterator = T*; |
| 46 | |
| 47 | iterator begin(); |
| 48 | iterator end(); |
| 49 | |
| 50 | T* data; |
| 51 | unsigned long sz; |
| 52 | }; |
| 53 | |
| 54 | } // namespace std |
| 55 | |
| 56 | struct Bar { |
| 57 | void Do(); |
| 58 | void ConstDo() const; |
| 59 | }; |
| 60 | struct BarPtr { |
| 61 | Bar* operator->(); |
| 62 | Bar& operator*(); |
| 63 | Bar* get(); |
| 64 | explicit operator bool() const; |
| 65 | }; |
| 66 | struct int_ptr { |
| 67 | int* get(); |
| 68 | int* operator->(); |
| 69 | int& operator*(); |
| 70 | }; |
| 71 | |
| 72 | struct Fail1 { |
| 73 | Bar* get(); |
| 74 | }; |
| 75 | struct Fail2 { |
| 76 | Bar* get(); |
| 77 | int* operator->(); |
| 78 | int& operator*(); |
| 79 | }; |
| 80 | |
| 81 | struct PointerWithOverloadedGet { |
| 82 | int* get(); |
| 83 | template <typename T> |
| 84 | T* get(); |
| 85 | int* operator->(); |
| 86 | int& operator*(); |
| 87 | }; |
| 88 | |
| 89 | void Positive() { |
| 90 | BarPtr u; |
| 91 | // CHECK-FIXES: BarPtr u; |
| 92 | BarPtr().get()->Do(); |
| 93 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant get() call on smart pointer [readability-redundant-smartptr-get] |
| 94 | // CHECK-MESSAGES: BarPtr().get()->Do(); |
| 95 | // CHECK-FIXES: BarPtr()->Do(); |
| 96 | |
| 97 | u.get()->ConstDo(); |
| 98 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant get() call |
| 99 | // CHECK-MESSAGES: u.get()->ConstDo(); |
| 100 | // CHECK-FIXES: u->ConstDo(); |
| 101 | |
| 102 | Bar& b = *BarPtr().get(); |
| 103 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call |
| 104 | // CHECK-MESSAGES: Bar& b = *BarPtr().get(); |
| 105 | // CHECK-FIXES: Bar& b = *BarPtr(); |
| 106 | |
| 107 | Bar& b2 = *std::unique_ptr<Bar>().get(); |
| 108 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant get() call |
| 109 | // CHECK-MESSAGES: Bar& b2 = *std::unique_ptr<Bar>().get(); |
| 110 | // CHECK-FIXES: Bar& b2 = *std::unique_ptr<Bar>(); |
| 111 | |
| 112 | (*BarPtr().get()).ConstDo(); |
| 113 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call |
| 114 | // CHECK-MESSAGES: (*BarPtr().get()).ConstDo(); |
| 115 | // CHECK-FIXES: (*BarPtr()).ConstDo(); |
| 116 | |
| 117 | (*std::unique_ptr<Bar>().get()).ConstDo(); |
| 118 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call |
| 119 | // CHECK-MESSAGES: (*std::unique_ptr<Bar>().get()).ConstDo(); |
| 120 | // CHECK-FIXES: (*std::unique_ptr<Bar>()).ConstDo(); |
| 121 | |
| 122 | std::unique_ptr<Bar>* up; |
| 123 | (*up->get()).Do(); |
| 124 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call |
| 125 | // CHECK-MESSAGES: (*up->get()).Do(); |
| 126 | // CHECK-FIXES: (**up).Do(); |
| 127 | |
| 128 | int_ptr ip; |
| 129 | int i = *ip.get(); |
| 130 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant get() call |
| 131 | // CHECK-MESSAGES: int i = *ip.get(); |
| 132 | // CHECK-FIXES: int i = *ip; |
| 133 | |
| 134 | auto ip2 = ip; |
| 135 | i = *ip2.get(); |
| 136 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 137 | // CHECK-MESSAGES: i = *ip2.get(); |
| 138 | // CHECK-FIXES: i = *ip2; |
| 139 | |
| 140 | std::unique_ptr<int> uu; |
| 141 | std::shared_ptr<double> *ss; |
| 142 | bool bb = uu.get() == nullptr; |
| 143 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call |
| 144 | // CHECK-MESSAGES: uu.get() == nullptr; |
| 145 | // CHECK-FIXES: bool bb = uu == nullptr; |
| 146 | |
| 147 | if (up->get()); |
| 148 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call |
| 149 | // CHECK-MESSAGES: if (up->get()); |
| 150 | // CHECK-FIXES: if (*up); |
| 151 | if ((uu.get())); |
| 152 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 153 | // CHECK-MESSAGES: if ((uu.get())); |
| 154 | // CHECK-FIXES: if ((uu)); |
| 155 | bb = !ss->get(); |
| 156 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant get() call |
| 157 | // CHECK-MESSAGES: bb = !ss->get(); |
| 158 | // CHECK-FIXES: bb = !*ss; |
| 159 | bb = u.get() ? true : false; |
| 160 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 161 | // CHECK-MESSAGES: bb = u.get() ? true : false; |
| 162 | // CHECK-FIXES: bb = u ? true : false; |
| 163 | |
| 164 | bb = nullptr != ss->get(); |
| 165 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: redundant get() call |
| 166 | // CHECK-MESSAGES: nullptr != ss->get(); |
| 167 | // CHECK-FIXES: bb = nullptr != *ss; |
| 168 | |
| 169 | i = *PointerWithOverloadedGet().get(); |
| 170 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 171 | // CHECK-MESSAGES: i = *PointerWithOverloadedGet().get(); |
| 172 | // CHECK-FIXES: i = *PointerWithOverloadedGet(); |
| 173 | |
| 174 | bb = std::unique_ptr<int>().get() == NULL; |
| 175 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 176 | // CHECK-MESSAGES: bb = std::unique_ptr<int>().get() == NULL; |
| 177 | // CHECK-FIXES: bb = std::unique_ptr<int>() == NULL; |
| 178 | bb = ss->get() == NULL; |
| 179 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 180 | // CHECK-MESSAGES: bb = ss->get() == NULL; |
| 181 | // CHECK-FIXES: bb = *ss == NULL; |
| 182 | |
| 183 | std::unique_ptr<int> x, y; |
| 184 | if (x.get() == nullptr); |
| 185 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call |
| 186 | // CHECK-MESSAGES: if (x.get() == nullptr); |
| 187 | // CHECK-FIXES: if (x == nullptr); |
| 188 | if (nullptr == y.get()); |
| 189 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant get() call |
| 190 | // CHECK-MESSAGES: if (nullptr == y.get()); |
| 191 | // CHECK-FIXES: if (nullptr == y); |
| 192 | if (x.get() == NULL); |
| 193 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call |
| 194 | // CHECK-MESSAGES: if (x.get() == NULL); |
| 195 | // CHECK-FIXES: if (x == NULL); |
| 196 | if (NULL == x.get()); |
| 197 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: redundant get() call |
| 198 | // CHECK-MESSAGES: if (NULL == x.get()); |
| 199 | // CHECK-FIXES: if (NULL == x); |
| 200 | } |
| 201 | |
| 202 | template <typename T> |
| 203 | void testTemplate() { |
| 204 | T().get()->Do(); |
| 205 | } |
| 206 | |
| 207 | template <typename T> |
| 208 | void testTemplate2() { |
| 209 | std::unique_ptr<T> up; |
| 210 | up.get()->Do(); |
| 211 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant get() call |
| 212 | // CHECK-FIXES: up->Do(); |
| 213 | } |
| 214 | |
| 215 | void instantiate() { |
| 216 | testTemplate<BarPtr>(); |
| 217 | testTemplate<std::unique_ptr<Bar>>(); |
| 218 | testTemplate<Fail2>(); |
| 219 | |
| 220 | testTemplate2<Bar>(); |
| 221 | } |
| 222 | |
| 223 | struct S { |
| 224 | |
| 225 | void foo() { |
| 226 | m_up.get()->Do(); |
| 227 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call |
| 228 | // CHECK-FIXES: m_up->Do(); |
| 229 | m_bp.get()->Do(); |
| 230 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call |
| 231 | // CHECK-FIXES: m_bp->Do(); |
| 232 | } |
| 233 | |
| 234 | std::unique_ptr<Bar> m_up; |
| 235 | BarPtr m_bp; |
| 236 | }; |
| 237 | |
| 238 | #define MACRO(p) p.get() |
| 239 | |
| 240 | void Negative() { |
| 241 | struct NegPtr { |
| 242 | int* get(); |
| 243 | int* operator->() { |
| 244 | return &*this->get(); |
| 245 | } |
| 246 | int& operator*() { |
| 247 | return *get(); |
| 248 | } |
| 249 | }; |
| 250 | |
| 251 | long l = *PointerWithOverloadedGet().get<long>(); |
| 252 | |
| 253 | std::unique_ptr<Bar>* u; |
| 254 | u->get()->Do(); |
| 255 | |
| 256 | Fail1().get()->Do(); |
| 257 | Fail2().get()->Do(); |
| 258 | const Bar& b = *Fail1().get(); |
| 259 | (*Fail2().get()).Do(); |
| 260 | |
| 261 | int_ptr ip; |
| 262 | bool bb = ip.get() == nullptr; |
| 263 | bb = !ip.get(); |
| 264 | bb = ip.get() ? true : false; |
| 265 | std::unique_ptr<int> x; |
| 266 | if (MACRO(x) == nullptr) |
| 267 | ; |
| 268 | } |
| 269 | |
| 270 | void test_redundant_get() { |
| 271 | std::vector<std::shared_ptr<int>> v; |
| 272 | auto f = [](int) {}; |
| 273 | for (auto i = v.begin(); i != v.end(); ++i) { |
| 274 | f(*i->get()); |
| 275 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 276 | // CHECK-FIXES: f(**i); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | struct Inner { |
| 281 | int a; |
| 282 | int *getValue() { return &a; } |
| 283 | }; |
| 284 | |
| 285 | struct Example { |
| 286 | Inner inner; |
| 287 | Inner* get() { return &inner; } |
| 288 | int *getValue() { return inner.getValue(); } |
| 289 | }; |
| 290 | |
| 291 | void test_redundant_get_with_member() { |
| 292 | std::vector<std::shared_ptr<Example>> v; |
| 293 | auto f = [](int) {}; |
| 294 | for (auto i = v.begin(); i != v.end(); ++i) { |
| 295 | f(*(*i).get()->get()->getValue()); |
| 296 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call |
| 297 | // CHECK-FIXES: f(**i->get()->getValue()); |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | void test_smart_ptr_to_array() { |
| 302 | std::unique_ptr<int[]> i; |
| 303 | // The array specialization does not have operator*(), so make sure |
| 304 | // we do not incorrectly suggest sizeof(*i) here. |
| 305 | // FIXME: alternatively, we could suggest sizeof(i[0]) |
| 306 | auto sz = sizeof(*i.get()); |
| 307 | |
| 308 | std::shared_ptr<Inner[]> s; |
| 309 | // The array specialization does not have operator->() either |
| 310 | s.get()->getValue(); |
| 311 | |
| 312 | bool b1 = !s.get(); |
| 313 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant get() call |
| 314 | // CHECK-FIXES: bool b1 = !s; |
| 315 | |
| 316 | if (s.get()) {} |
| 317 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call |
| 318 | // CHECK-FIXES: if (s) {} |
| 319 | |
| 320 | int x = s.get() ? 1 : 2; |
| 321 | // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant get() call |
| 322 | // CHECK-FIXES: int x = s ? 1 : 2; |
| 323 | |
| 324 | bool b2 = s.get() == nullptr; |
| 325 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call |
| 326 | // CHECK-FIXES: bool b2 = s == nullptr; |
| 327 | } |
| 328 | |