xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion.cpp (revision 69937982dbdd73172ec06580f6f93616edca8e9e)
1 // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-optional-value-conversion %t -- --fix-notes
2 // RUN: %check_clang_tidy -check-suffix=CUSTOM -std=c++17-or-later %s bugprone-optional-value-conversion %t -- \
3 // RUN: -config="{CheckOptions: {bugprone-optional-value-conversion.OptionalTypes: 'CustomOptional', \
4 // RUN:                          bugprone-optional-value-conversion.ValueMethods: '::Read$;::Ooo$'}}" --fix-notes
5 
6 namespace std {
7   template<typename T>
8   struct optional
9   {
10     constexpr optional() noexcept;
11     constexpr optional(T&&) noexcept;
12     constexpr optional(const T&) noexcept;
13     template<typename U>
14     constexpr optional(U&&) noexcept;
15     const T& operator*() const;
16     T* operator->();
17     const T* operator->() const;
18     T& operator*();
19     const T& value() const;
20     T& value();
21     const T& get() const;
22     T& get();
23     T value_or(T) const;
24   };
25 
26   template <class T>
move(T & x)27   T&& move(T &x) {
28     return static_cast<T&&>(x);
29   }
30 }
31 
32 namespace boost {
33   template<typename T>
34   struct optional {
35     constexpr optional() noexcept;
36     constexpr optional(const T&) noexcept;
37     const T& operator*() const;
38     const T& get() const;
39   };
40 }
41 
42 namespace absl {
43   template<typename T>
44   struct optional {
45     constexpr optional() noexcept;
46     constexpr optional(const T&) noexcept;
47     const T& operator*() const;
48     const T& value() const;
49   };
50 }
51 
52 template<typename T>
53 struct CustomOptional {
54   CustomOptional();
55   CustomOptional(const T&);
56   const T& Read() const;
57   T& operator*();
58   T& Ooo();
59 };
60 
61 void takeOptionalValue(std::optional<int>);
62 void takeOptionalRef(const std::optional<int>&);
63 void takeOptionalRRef(std::optional<int>&&);
64 void takeOtherOptional(std::optional<long>);
65 void takeBOptionalValue(boost::optional<int>);
66 void takeAOptionalValue(absl::optional<int>);
67 
incorrect(std::optional<int> param)68 void incorrect(std::optional<int> param)
69 {
70   std::optional<int>* ptr = &param;
71   takeOptionalValue(**ptr);
72   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
73   // CHECK-FIXES: takeOptionalValue(*ptr);
74   takeOptionalValue(*param);
75   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
76   // CHECK-FIXES: takeOptionalValue(param);
77   takeOptionalValue(param.value());
78   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
79   // CHECK-FIXES: takeOptionalValue(param);
80   takeOptionalValue(ptr->value());
81   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
82   // CHECK-FIXES: takeOptionalValue(*ptr);
83   takeOptionalValue(param.operator*());
84   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
85   // CHECK-FIXES: takeOptionalValue(param);
86   takeOptionalValue(ptr->operator*());
87   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
88   // CHECK-FIXES: takeOptionalValue(*ptr);
89   takeOptionalRef(*param);
90   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
91   // CHECK-FIXES: takeOptionalRef(param);
92   takeOptionalRef(param.value());
93   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
94   // CHECK-FIXES: takeOptionalRef(param);
95   takeOptionalRef(ptr->value());
96   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
97   // CHECK-FIXES: takeOptionalRef(*ptr);
98   takeOptionalRef(param.operator*());
99   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
100   // CHECK-FIXES: takeOptionalRef(param);
101   takeOptionalRef(ptr->operator*());
102   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
103   // CHECK-FIXES: takeOptionalRef(*ptr);
104   std::optional<int> p = *param;
105   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
106   // CHECK-FIXES: std::optional<int> p = param;
107 
108   takeOptionalValue(std::move(**ptr));
109   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
110   // CHECK-FIXES: takeOptionalValue(std::move(*ptr));
111   takeOptionalValue(std::move(*param));
112   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
113   // CHECK-FIXES: takeOptionalValue(std::move(param));
114   takeOptionalValue(std::move(param.value()));
115   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
116   // CHECK-FIXES: takeOptionalValue(std::move(param));
117   takeOptionalValue(std::move(ptr->value()));
118   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
119   // CHECK-FIXES: takeOptionalValue(std::move(*ptr));
120   takeOptionalValue(std::move(param.operator*()));
121   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
122   // CHECK-FIXES: takeOptionalValue(std::move(param));
123   takeOptionalRef(std::move(*param));
124   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
125   // CHECK-FIXES: takeOptionalRef(std::move(param));
126   takeOptionalRef(std::move(param.value()));
127   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
128   // CHECK-FIXES: takeOptionalRef(std::move(param));
129   takeOptionalRef(std::move(ptr->value()));
130   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
131   // CHECK-FIXES: takeOptionalRef(std::move(*ptr));
132   takeOptionalRef(std::move(param.operator*()));
133   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
134   // CHECK-FIXES: takeOptionalRef(std::move(param));
135   takeOptionalRRef(std::move(*param));
136   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
137   // CHECK-FIXES: takeOptionalRRef(std::move(param));
138   takeOptionalRRef(std::move(param.value()));
139   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
140   // CHECK-FIXES: takeOptionalRRef(std::move(param));
141   takeOptionalRRef(std::move(ptr->value()));
142   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
143   // CHECK-FIXES: takeOptionalRRef(std::move(*ptr));
144   takeOptionalRRef(std::move(param.operator*()));
145   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
146   // CHECK-FIXES: takeOptionalRRef(std::move(param));
147   takeOptionalRRef(std::move(ptr->operator*()));
148   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
149   // CHECK-FIXES: takeOptionalRRef(std::move(*ptr));
150   std::optional<int> p2 = std::move(*param);
151   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
152   // CHECK-FIXES: std::optional<int> p2 = std::move(param);
153 
154   std::optional<std::optional<int>> opt;
155   takeOptionalValue(opt->value());
156   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
157   // CHECK-FIXES: takeOptionalValue(*opt);
158   takeOptionalValue(opt->operator*());
159   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
160   // CHECK-FIXES: takeOptionalValue(*opt);
161 
162   boost::optional<int> bopt;
163   takeBOptionalValue(*bopt);
164   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'boost::optional<int>' into 'int' and back into 'boost::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
165   // CHECK-FIXES: takeBOptionalValue(bopt);
166   takeBOptionalValue(bopt.get());
167   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'boost::optional<int>' into 'int' and back into 'boost::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
168   // CHECK-FIXES: takeBOptionalValue(bopt);
169 
170   absl::optional<int> aopt;
171   takeAOptionalValue(*aopt);
172   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'absl::optional<int>' into 'int' and back into 'absl::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
173   // CHECK-FIXES: takeAOptionalValue(aopt);
174   takeAOptionalValue(aopt.value());
175   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'absl::optional<int>' into 'int' and back into 'absl::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
176   // CHECK-FIXES: takeAOptionalValue(aopt);
177 }
178 
179 void takeCustom(const CustomOptional<int>&);
180 
testCustom(CustomOptional<int> param)181 void testCustom(CustomOptional<int> param) {
182   takeCustom(*param);
183   // CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
184   // CHECK-FIXES-CUSTOM: takeCustom(param);
185   takeCustom(param.Read());
186   // CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
187   // CHECK-FIXES-CUSTOM: takeCustom(param);
188   takeCustom(param.Ooo());
189   // CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
190   // CHECK-FIXES-CUSTOM: takeCustom(param);
191 }
192 
correct(std::optional<int> param)193 void correct(std::optional<int> param)
194 {
195   takeOtherOptional(*param);
196   takeOtherOptional(param.value());
197   takeOtherOptional(param.value_or(5U));
198   takeOtherOptional(param.operator*());
199 
200   std::optional<long> p = *param;
201   takeOptionalValue(param.value_or(5U));
202   takeOptionalRef(param.value_or(5U));
203 
204   std::optional<int>* ptr = &param;
205   takeOtherOptional(**ptr);
206   takeOtherOptional(ptr->value());
207   takeOtherOptional(ptr->value_or(5U));
208   takeOtherOptional(ptr->operator*());
209 
210   std::optional<long>* p2 = &p;
211   takeOptionalValue(p2->value_or(5U));
212   takeOptionalRef(p2->value_or(5U));
213 
214   using Type = decltype(takeOptionalValue(*param));
215 }
216