1 .. title:: clang-tidy - bugprone-easily-swappable-parameters
3 bugprone-easily-swappable-parameters
4 ====================================
6 Finds function definitions where parameters of convertible types follow each
7 other directly, making call sites prone to calling the function with
8 swapped (or badly ordered) arguments.
12 void drawPoint(int X, int Y) { /* ... */ }
13 FILE *open(const char *Dir, const char *Name, Flags Mode) { /* ... */ }
15 A potential call like ``drawPoint(-2, 5)`` or ``openPath("a.txt", "tmp", Read)``
16 is perfectly legal from the language's perspective, but might not be what the
17 developer of the function intended.
19 More elaborate and type-safe constructs, such as opaque typedefs or strong
20 types should be used instead, to prevent a mistaken order of arguments.
24 struct Coord2D { int X; int Y; };
25 void drawPoint(const Coord2D Pos) { /* ... */ }
27 FILE *open(const Path &Dir, const Filename &Name, Flags Mode) { /* ... */ }
29 Due to the potentially elaborate refactoring and API-breaking that is necessary
30 to strengthen the type safety of a project, no automatic fix-its are offered.
35 Extension/relaxation options
36 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38 Relaxation (or extension) options can be used to broaden the scope of the
39 analysis and fine-tune the enabling of more mixes between types.
40 Some mixes may depend on coding style or preference specific to a project,
41 however, it should be noted that enabling *all* of these relaxations model the
42 way of mixing at call sites the most.
43 These options are expected to make the check report for more functions, and
44 report longer mixable ranges.
46 .. option:: QualifiersMix
48 Whether to consider parameters of some *cvr-qualified* ``T`` and a
49 differently *cvr-qualified* ``T`` (i.e. ``T`` and ``const T``, ``const T``
50 and ``volatile T``, etc.) mixable between one another.
51 If `false`, the check will consider differently qualified types unmixable.
52 `True` turns the warnings on.
55 The following example produces a diagnostic only if `QualifiersMix` is
60 void *memcpy(const void *Destination, void *Source, std::size_t N) { /* ... */ }
62 .. option:: ModelImplicitConversions
64 Whether to consider parameters of type ``T`` and ``U`` mixable if there
65 exists an implicit conversion from ``T`` to ``U`` and ``U`` to ``T``.
66 If `false`, the check will not consider implicitly convertible types for
68 `True` turns warnings for implicit conversions on.
71 The following examples produce a diagnostic only if
72 `ModelImplicitConversions` is enabled:
76 void fun(int Int, double Double) { /* ... */ }
77 void compare(const char *CharBuf, std::string String) { /* ... */ }
81 Changing the qualifiers of an expression's type (e.g. from ``int`` to
82 ``const int``) is defined as an *implicit conversion* in the C++
84 However, the check separates this decision-making on the mixability of
85 differently qualified types based on whether `QualifiersMix` was
88 For example, the following code snippet will only produce a diagnostic
89 if **both** `QualifiersMix` and `ModelImplicitConversions` are enabled:
93 void fun2(int Int, const double Double) { /* ... */ }
98 Filtering options can be used to lessen the size of the diagnostics emitted by
99 the checker, whether the aim is to ignore certain constructs or dampen the
102 .. option:: MinimumLength
104 The minimum length required from an adjacent parameter sequence to be
107 Might be any positive integer greater or equal to `2`.
108 If `0` or `1` is given, the default value `2` will be used instead.
110 For example, if `3` is specified, the examples above will not be matched.
112 .. option:: IgnoredParameterNames
114 The list of parameter **names** that should never be considered part of a
115 swappable adjacent parameter sequence.
116 The value is a `;`-separated list of names.
117 To ignore unnamed parameters, add `""` to the list verbatim (not the
118 empty string, but the two quotes, potentially escaped!).
119 **This option is case-sensitive!**
121 By default, the following parameter names, and their Uppercase-initial
122 variants are ignored:
123 `""` (unnamed parameters), `iterator`, `begin`, `end`, `first`, `last`,
126 .. option:: IgnoredParameterTypeSuffixes
128 The list of parameter **type name suffixes** that should never be
129 considered part of a swappable adjacent parameter sequence.
130 Parameters which type, as written in the source code, end with an element
131 of this option will be ignored.
132 The value is a `;`-separated list of names.
133 **This option is case-sensitive!**
135 By default, the following, and their lowercase-initial variants are ignored:
136 `bool`, `It`, `Iterator`, `InputIt`, `ForwardIt`, `BidirIt`, `RandomIt`,
137 `random_iterator`, `ReverseIt`, `reverse_iterator`,
138 `reverse_const_iterator`, `RandomIt`, `random_iterator`, `ReverseIt`,
139 `reverse_iterator`, `reverse_const_iterator`, `Const_Iterator`,
140 `ConstIterator`, `const_reverse_iterator`, `ConstReverseIterator`.
141 In addition, `_Bool` (but not `_bool`) is also part of the default value.
143 .. option:: SuppressParametersUsedTogether
145 Suppresses diagnostics about parameters that are used together or in a
146 similar fashion inside the function's body.
148 Specifying `false` will turn off the heuristics.
150 Currently, the following heuristics are implemented which will suppress the
151 warning about the parameter pair involved:
153 * The parameters are used in the same expression, e.g. ``f(a, b)`` or
155 * The parameters are further passed to the same function to the same
156 parameter of that function, of the same overload.
157 E.g. ``f(a, 1)`` and ``f(b, 2)`` to some ``f(T, int)``.
161 The check does not perform path-sensitive analysis, and as such,
162 "same function" in this context means the same function declaration.
163 If the same member function of a type on two distinct instances are
164 called with the parameters, it will still be regarded as
167 * The same member field is accessed, or member method is called of the
168 two parameters, e.g. ``a.foo()`` and ``b.foo()``.
169 * Separate ``return`` statements return either of the parameters on
170 different code paths.
172 .. option:: NamePrefixSuffixSilenceDissimilarityTreshold
174 The number of characters two parameter names might be different on *either*
175 the head or the tail end with the rest of the name the same so that the
176 warning about the two parameters are silenced.
178 Might be any positive integer.
179 If `0`, the filtering heuristic based on the parameters' names is turned
182 This option can be used to silence warnings about parameters where the
183 naming scheme indicates that the order of those parameters do not matter.
185 For example, the parameters ``LHS`` and ``RHS`` are 1-dissimilar suffixes
186 of each other: ``L`` and ``R`` is the different character, while ``HS``
187 is the common suffix.
188 Similarly, parameters ``text1, text2, text3`` are 1-dissimilar prefixes
189 of each other, with the numbers at the end being the dissimilar part.
190 If the value is at least `1`, such cases will not be reported.
196 **This check is designed to check function signatures!**
198 The check does not investigate functions that are generated by the compiler
199 in a context that is only determined from a call site.
200 These cases include variadic functions, functions in C code that do not have
201 an argument list, and C++ template instantiations.
202 Most of these cases, which are otherwise swappable from a caller's standpoint,
203 have no way of getting "fixed" at the definition point.
204 In the case of C++ templates, only primary template definitions and explicit
205 specializations are matched and analyzed.
207 None of the following cases produce a diagnostic:
211 int printf(const char *Format, ...) { /* ... */ }
212 int someOldCFunction() { /* ... */ }
214 template <typename T, typename U>
215 int add(T X, U Y) { return X + Y };
217 void theseAreNotWarnedAbout() {
218 printf("%d %d\n", 1, 2); // Two ints passed, they could be swapped.
219 someOldCFunction(1, 2, 3); // Similarly, multiple ints passed.
221 add(1, 2); // Instantiates 'add<int, int>', but that's not a user-defined function.
224 Due to the limitation above, parameters which type are further dependent upon
225 template instantiations to *prove* that they mix with another parameter's is
230 template <typename T>
232 typedef T element_type;
235 // Diagnosed: Explicit instantiation was done by the user, we can prove it
237 void instantiated(int A, Vector<int>::element_type B) { /* ... */ }
239 // Diagnosed: The two parameter types are exactly the same.
240 template <typename T>
241 void exact(typename Vector<T>::element_type A,
242 typename Vector<T>::element_type B) { /* ... */ }
244 // Skipped: The two parameters are both 'T' but we cannot prove this
245 // without actually instantiating.
246 template <typename T>
247 void falseNegative(T A, typename Vector<T>::element_type B) { /* ... */ }
249 In the context of *implicit conversions* (when `ModelImplicitConversions` is
250 enabled), the modelling performed by the check
251 warns if the parameters are swappable and the swapped order matches implicit
253 It does not model whether there exists an unrelated third type from which
254 *both* parameters can be given in a function call.
255 This means that in the following example, even while ``strs()`` clearly carries
256 the possibility to be called with swapped arguments (as long as the arguments
257 are string literals), will not be warned about.
262 String(const char *Buf);
266 StringView(const char *Buf);
267 operator const char *() const;
270 // Skipped: Directly swapping expressions of the two type cannot mix.
271 // (Note: StringView -> const char * -> String would be **two**
272 // user-defined conversions, which is disallowed by the language.)
273 void strs(String Str, StringView SV) { /* ... */ }
275 // Diagnosed: StringView implicitly converts to and from a buffer.
276 void cStr(StringView SV, const char *Buf() { /* ... */ }