xref: /llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone/easily-swappable-parameters.rst (revision 6e566bc5523f743bc34a7e26f050f1f2b4d699a8)
1.. title:: clang-tidy - bugprone-easily-swappable-parameters
2
3bugprone-easily-swappable-parameters
4====================================
5
6Finds function definitions where parameters of convertible types follow each
7other directly, making call sites prone to calling the function with
8swapped (or badly ordered) arguments.
9
10.. code-block:: c++
11
12    void drawPoint(int X, int Y) { /* ... */ }
13    FILE *open(const char *Dir, const char *Name, Flags Mode) { /* ... */ }
14
15A potential call like ``drawPoint(-2, 5)`` or ``openPath("a.txt", "tmp", Read)``
16is perfectly legal from the language's perspective, but might not be what the
17developer of the function intended.
18
19More elaborate and type-safe constructs, such as opaque typedefs or strong
20types should be used instead, to prevent a mistaken order of arguments.
21
22.. code-block:: c++
23
24    struct Coord2D { int X; int Y; };
25    void drawPoint(const Coord2D Pos) { /* ... */ }
26
27    FILE *open(const Path &Dir, const Filename &Name, Flags Mode) { /* ... */ }
28
29Due to the potentially elaborate refactoring and API-breaking that is necessary
30to strengthen the type safety of a project, no automatic fix-its are offered.
31
32Options
33-------
34
35Extension/relaxation options
36^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37
38Relaxation (or extension) options can be used to broaden the scope of the
39analysis and fine-tune the enabling of more mixes between types.
40Some mixes may depend on coding style or preference specific to a project,
41however, it should be noted that enabling *all* of these relaxations model the
42way of mixing at call sites the most.
43These options are expected to make the check report for more functions, and
44report longer mixable ranges.
45
46.. option:: QualifiersMix
47
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.
53    Defaults to `false`.
54
55    The following example produces a diagnostic only if `QualifiersMix` is
56    enabled:
57
58    .. code-block:: c++
59
60        void *memcpy(const void *Destination, void *Source, std::size_t N) { /* ... */ }
61
62.. option:: ModelImplicitConversions
63
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
67    mixability.
68    `True` turns warnings for implicit conversions on.
69    Defaults to `true`.
70
71    The following examples produce a diagnostic only if
72    `ModelImplicitConversions` is enabled:
73
74    .. code-block:: c++
75
76        void fun(int Int, double Double) { /* ... */ }
77        void compare(const char *CharBuf, std::string String) { /* ... */ }
78
79    .. note::
80
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++
83        Standard.
84        However, the check separates this decision-making on the mixability of
85        differently qualified types based on whether `QualifiersMix` was
86        enabled.
87
88        For example, the following code snippet will only produce a diagnostic
89        if **both** `QualifiersMix` and `ModelImplicitConversions` are enabled:
90
91        .. code-block:: c++
92
93            void fun2(int Int, const double Double) { /* ... */ }
94
95Filtering options
96^^^^^^^^^^^^^^^^^
97
98Filtering options can be used to lessen the size of the diagnostics emitted by
99the checker, whether the aim is to ignore certain constructs or dampen the
100noisiness.
101
102.. option:: MinimumLength
103
104    The minimum length required from an adjacent parameter sequence to be
105    diagnosed.
106    Defaults to `2`.
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.
109
110    For example, if `3` is specified, the examples above will not be matched.
111
112.. option:: IgnoredParameterNames
113
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!**
120
121    By default, the following parameter names, and their Uppercase-initial
122    variants are ignored:
123    `""` (unnamed parameters), `iterator`, `begin`, `end`, `first`, `last`,
124    `lhs`, `rhs`.
125
126.. option:: IgnoredParameterTypeSuffixes
127
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!**
134
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.
142
143.. option:: SuppressParametersUsedTogether
144
145    Suppresses diagnostics about parameters that are used together or in a
146    similar fashion inside the function's body.
147    Defaults to `true`.
148    Specifying `false` will turn off the heuristics.
149
150    Currently, the following heuristics are implemented which will suppress the
151    warning about the parameter pair involved:
152
153    * The parameters are used in the same expression, e.g. ``f(a, b)`` or
154      ``a < b``.
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)``.
158
159      .. note::
160
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
165        "same function".
166
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.
171
172.. option:: NamePrefixSuffixSilenceDissimilarityTreshold
173
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.
177    Defaults to `1`.
178    Might be any positive integer.
179    If `0`, the filtering heuristic based on the parameters' names is turned
180    off.
181
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.
184
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.
191
192
193Limitations
194-----------
195
196**This check is designed to check function signatures!**
197
198The check does not investigate functions that are generated by the compiler
199in a context that is only determined from a call site.
200These cases include variadic functions, functions in C code that do not have
201an argument list, and C++ template instantiations.
202Most of these cases, which are otherwise swappable from a caller's standpoint,
203have no way of getting "fixed" at the definition point.
204In the case of C++ templates, only primary template definitions and explicit
205specializations are matched and analyzed.
206
207None of the following cases produce a diagnostic:
208
209.. code-block:: c++
210
211    int printf(const char *Format, ...) { /* ... */ }
212    int someOldCFunction() { /* ... */ }
213
214    template <typename T, typename U>
215    int add(T X, U Y) { return X + Y };
216
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.
220
221        add(1, 2); // Instantiates 'add<int, int>', but that's not a user-defined function.
222    }
223
224Due to the limitation above, parameters which type are further dependent upon
225template instantiations to *prove* that they mix with another parameter's is
226not diagnosed.
227
228.. code-block:: c++
229
230    template <typename T>
231    struct Vector {
232      typedef T element_type;
233    };
234
235    // Diagnosed: Explicit instantiation was done by the user, we can prove it
236    // is the same type.
237    void instantiated(int A, Vector<int>::element_type B) { /* ... */ }
238
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) { /* ... */ }
243
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) { /* ... */ }
248
249In the context of *implicit conversions* (when `ModelImplicitConversions` is
250enabled), the modelling performed by the check
251warns if the parameters are swappable and the swapped order matches implicit
252conversions.
253It does not model whether there exists an unrelated third type from which
254*both* parameters can be given in a function call.
255This means that in the following example, even while ``strs()`` clearly carries
256the possibility to be called with swapped arguments (as long as the arguments
257are string literals), will not be warned about.
258
259.. code-block:: c++
260
261    struct String {
262        String(const char *Buf);
263    };
264
265    struct StringView {
266        StringView(const char *Buf);
267        operator const char *() const;
268    };
269
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) { /* ... */ }
274
275    // Diagnosed: StringView implicitly converts to and from a buffer.
276    void cStr(StringView SV, const char *Buf() { /* ... */ }
277