File: easily-swappable-parameters-implicits.cpp

package info (click to toggle)
llvm-toolchain-17 1%3A17.0.6-22
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,799,624 kB
  • sloc: cpp: 6,428,607; ansic: 1,383,196; asm: 793,408; python: 223,504; objc: 75,364; f90: 60,502; lisp: 33,869; pascal: 15,282; sh: 9,684; perl: 7,453; ml: 4,937; awk: 3,523; makefile: 2,889; javascript: 2,149; xml: 888; fortran: 619; cs: 573
file content (349 lines) | stat: -rw-r--r-- 17,352 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-easily-swappable-parameters %t \
// RUN:   -config='{CheckOptions: [ \
// RUN:     {key: bugprone-easily-swappable-parameters.MinimumLength, value: 2}, \
// RUN:     {key: bugprone-easily-swappable-parameters.IgnoredParameterNames, value: ""}, \
// RUN:     {key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes, value: ""}, \
// RUN:     {key: bugprone-easily-swappable-parameters.QualifiersMix, value: 0}, \
// RUN:     {key: bugprone-easily-swappable-parameters.ModelImplicitConversions, value: 1}, \
// RUN:     {key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether, value: 0}, \
// RUN:     {key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold, value: 0} \
// RUN:  ]}' --

void implicitDoesntBreakOtherStuff(int A, int B) {}
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: 2 adjacent parameters of 'implicitDoesntBreakOtherStuff' of similar type ('int') are easily swapped by mistake [bugprone-easily-swappable-parameters]
// CHECK-MESSAGES: :[[@LINE-2]]:40: note: the first parameter in the range is 'A'
// CHECK-MESSAGES: :[[@LINE-3]]:47: note: the last parameter in the range is 'B'

void arrayAndPtr1(int *IP, int IA[]) { arrayAndPtr1(IA, IP); }
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 2 adjacent parameters of 'arrayAndPtr1' of similar type ('int *')
// CHECK-MESSAGES: :[[@LINE-2]]:24: note: the first parameter in the range is 'IP'
// CHECK-MESSAGES: :[[@LINE-3]]:32: note: the last parameter in the range is 'IA'

void arrayAndPtr2(int *IP, int IA[8]) { arrayAndPtr2(IA, IP); }
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 2 adjacent parameters of 'arrayAndPtr2' of similar type ('int *')
// CHECK-MESSAGES: :[[@LINE-2]]:24: note: the first parameter in the range is 'IP'
// CHECK-MESSAGES: :[[@LINE-3]]:32: note: the last parameter in the range is 'IA'

void arrayAndElement(int I, int IA[]) {} // NO-WARN.

typedef int Point2D[2];
typedef int Point3D[3];

void arrays1(Point2D P2D, Point3D P3D) {} // In reality this is (int*, int*).
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 2 adjacent parameters of 'arrays1' of similar type ('int *') are
// CHECK-MESSAGES: :[[@LINE-2]]:22: note: the first parameter in the range is 'P2D'
// CHECK-MESSAGES: :[[@LINE-3]]:35: note: the last parameter in the range is 'P3D'

void crefToArrayTypedef1(int I, const Point2D &P) {}
// NO-WARN.

void crefToArrayTypedef2(int *IA, const Point2D &P) {}
// NO-WARN.

void crefToArrayTypedef3(int P1[2], const Point2D &P) {}
// NO-WARN.

void crefToArrayTypedefBoth1(const Point2D &VecDescartes, const Point3D &VecThreeD) {}
// NO-WARN: Distinct types.

template <int N, int M>
void templatedArrayRef(int (&Array1)[N], int (&Array2)[M]) {}
// NO-WARN: Distinct template types in the primary template.

void templatedArrayRefTest() {
  int Foo[12], Bar[12];
  templatedArrayRef(Foo, Bar);

  int Baz[12], Quux[42];
  templatedArrayRef(Baz, Quux);

  // NO-WARN: Implicit instantiations are not checked.
}

template <>
void templatedArrayRef(int (&Array1)[8], int (&Array2)[8]) { templatedArrayRef(Array2, Array1); }
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 2 adjacent parameters of 'templatedArrayRef<8, 8>' of similar type ('int (&)[8]') are
// CHECK-MESSAGES: :[[@LINE-2]]:30: note: the first parameter in the range is 'Array1'
// CHECK-MESSAGES: :[[@LINE-3]]:48: note: the last parameter in the range is 'Array2'

template <>
void templatedArrayRef(int (&Array1)[16], int (&Array2)[24]) {}
// NO-WARN: Not the same type.

void numericConversion1(int I, double D) { numericConversion1(D, I); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion1' of convertible types are easily swapped by mistake [bugprone-easily-swappable-parameters]
// CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:39: note: the last parameter in the range is 'D'
// CHECK-MESSAGES: :[[@LINE-4]]:32: note: 'int' and 'double' may be implicitly converted{{$}}

void numericConversion2(int I, short S) { numericConversion2(S, I); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion2' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:38: note: the last parameter in the range is 'S'
// CHECK-MESSAGES: :[[@LINE-4]]:32: note: 'int' and 'short' may be implicitly converted{{$}}

void numericConversion3(float F, unsigned long long ULL) { numericConversion3(ULL, F); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion3' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:31: note: the first parameter in the range is 'F'
// CHECK-MESSAGES: :[[@LINE-3]]:53: note: the last parameter in the range is 'ULL'
// CHECK-MESSAGES: :[[@LINE-4]]:34: note: 'float' and 'unsigned long long' may be implicitly converted{{$}}

enum Unscoped { U_A,
                U_B };
enum UnscopedFixed : char { UF_A,
                            UF_B };
enum struct Scoped { A,
                     B };

void numericConversion4(int I, Unscoped U) {} // NO-WARN.

void numericConversion5(int I, UnscopedFixed UF) {} // NO-WARN.

void numericConversion6(int I, Scoped S) {} // NO-WARN.

void numericConversion7(double D, Unscoped U) {} // NO-WARN.

void numericConversion8(double D, UnscopedFixed UF) {} // NO-WARN.

void numericConversion9(double D, Scoped S) {} // NO-WARN.

void numericConversionMultiUnique(int I, double D1, double D2) {}
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 3 adjacent parameters of 'numericConversionMultiUnique' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:39: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:60: note: the last parameter in the range is 'D2'
// CHECK-MESSAGES: :[[@LINE-4]]:42: note: 'int' and 'double' may be implicitly converted{{$}}
// (Note: int<->double conversion for I<->D2 not diagnosed again.)

typedef int MyInt;
using MyDouble = double;

void numericConversion10(MyInt MI, MyDouble MD) { numericConversion10(MD, MI); }
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 2 adjacent parameters of 'numericConversion10' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:32: note: the first parameter in the range is 'MI'
// CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'MD'
// CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'MyInt' and 'MyDouble' may be implicitly converted: 'MyInt' (as 'int') -> 'MyDouble' (as 'double'), 'MyDouble' (as 'double') -> 'MyInt' (as 'int')

void numericAndQualifierConversion(int I, const double CD) { numericAndQualifierConversion(CD, I); }
// NO-WARN: Qualifier mixing is handled by a different check option.

struct FromInt {
  FromInt(int);
};

void oneWayConversion1(int I, FromInt FI) {} // NO-WARN: One-way.

struct AmbiguousConvCtor {
  AmbiguousConvCtor(int);
  AmbiguousConvCtor(double);
};

void ambiguous1(long L, AmbiguousConvCtor ACC) {} // NO-WARN: Ambiguous, one-way.

struct ToInt {
  operator int() const;
};

void oneWayConversion2(ToInt TI, int I) {} // NO-WARN: One-way.

struct AmbiguousConvOp {
  operator int() const;
  operator double() const;
};

void ambiguous2(AmbiguousConvOp ACO, long L) {} // NO-WARN: Ambiguous, one-way.

struct AmbiguousEverything1;
struct AmbiguousEverything2;
struct AmbiguousEverything1 {
  AmbiguousEverything1();
  AmbiguousEverything1(AmbiguousEverything2);
  operator AmbiguousEverything2() const;
};
struct AmbiguousEverything2 {
  AmbiguousEverything2();
  AmbiguousEverything2(AmbiguousEverything1);
  operator AmbiguousEverything1() const;
};

void ambiguous3(AmbiguousEverything1 AE1, AmbiguousEverything2 AE2) {} // NO-WARN: Ambiguous.

struct Integer {
  Integer(int);
  operator int() const;
};

void userDefinedConversion1(int I1, Integer I2) { userDefinedConversion1(I2, I1); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion1' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I1'
// CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'I2'
// CHECK-MESSAGES: :[[@LINE-4]]:37: note: 'int' and 'Integer' may be implicitly converted{{$}}
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here

struct Ambiguous {
  Ambiguous(int);
  Ambiguous(double);
  operator long() const;
  operator float() const;
};

void ambiguous3(char C, Ambiguous A) {} // NO-WARN: Ambiguous.

struct CDouble {
  CDouble(const double &);
  operator const double &() const;
};

void userDefinedConversion2(double D, CDouble CD) { userDefinedConversion2(CD, D); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion2' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'D'
// CHECK-MESSAGES: :[[@LINE-3]]:47: note: the last parameter in the range is 'CD'
// CHECK-MESSAGES: :[[@LINE-4]]:39: note: 'double' and 'CDouble' may be implicitly converted: 'double' -> 'const double &' -> 'CDouble', 'CDouble' -> 'const double &' -> 'double'
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here

void userDefinedConversion3(int I, CDouble CD) { userDefinedConversion3(CD, I); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion3' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:44: note: the last parameter in the range is 'CD'
// CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'CDouble' may be implicitly converted: 'int' -> 'double' -> 'const double &' -> 'CDouble', 'CDouble' -> 'const double &' -> 'int'
// CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the conversion operator declared here

struct TDInt {
  TDInt(const MyInt &);
  operator MyInt() const;
};

void userDefinedConversion4(int I, TDInt TDI) { userDefinedConversion4(TDI, I); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion4' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:42: note: the last parameter in the range is 'TDI'
// CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'TDInt' may be implicitly converted: 'int' -> 'const MyInt &' -> 'TDInt', 'TDInt' -> 'MyInt' -> 'int'
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here

struct TDIntDouble {
  TDIntDouble(const MyInt &);
  TDIntDouble(const MyDouble &);
  operator MyInt() const;
  operator MyDouble() const;
};

void userDefinedConversion5(int I, TDIntDouble TDID) { userDefinedConversion5(TDID, I); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion5' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
// CHECK-MESSAGES: :[[@LINE-3]]:48: note: the last parameter in the range is 'TDID'
// CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'TDIntDouble' may be implicitly converted: 'int' -> 'const MyInt &' -> 'TDIntDouble', 'TDIntDouble' -> 'MyInt' -> 'int'
// CHECK-MESSAGES: :[[@LINE-11]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the conversion operator declared here

void userDefinedConversion6(double D, TDIntDouble TDID) { userDefinedConversion6(TDID, D); }
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion6' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'D'
// CHECK-MESSAGES: :[[@LINE-3]]:51: note: the last parameter in the range is 'TDID'
// CHECK-MESSAGES: :[[@LINE-4]]:39: note: 'double' and 'TDIntDouble' may be implicitly converted: 'double' -> 'const MyDouble &' -> 'TDIntDouble', 'TDIntDouble' -> 'MyDouble' -> 'double'
// CHECK-MESSAGES: :[[@LINE-18]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the conversion operator declared here

void userDefinedConversion7(char C, TDIntDouble TDID) {} // NO-WARN: Ambiguous.

struct Forward1;
struct Forward2;

void incomplete(Forward1 *F1, Forward2 *F2) {} // NO-WARN: Do not compare incomplete types.

void pointeeConverison(int *IP, double *DP) {} // NO-WARN.

void pointerConversion1(void *VP, int *IP) {} // NO-WARN: One-way.

struct PointerBox {
  PointerBox(void *);
  operator int *() const;
};

void pointerConversion2(PointerBox PB, int *IP) { pointerConversion2(IP, PB); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion2' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'PB'
// CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'IP'
// CHECK-MESSAGES: :[[@LINE-4]]:40: note: 'PointerBox' and 'int *' may be implicitly converted: 'PointerBox' -> 'int *', 'int *' -> 'void *' -> 'PointerBox'
// CHECK-MESSAGES: :[[@LINE-8]]:3: note: the implicit conversion involves the conversion operator declared here
// CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the converting constructor declared here

void pointerConversion3(PointerBox PB, double *DP) {} // NO-WARN: Not convertible.

struct Base {};
struct Derived : Base {};

void pointerConversion4(Base *BP, Derived *DP) {} // NO-WARN: One-way.

struct BaseAndDerivedInverter {
  BaseAndDerivedInverter(Base); // Takes a Base
  operator Derived() const;     // and becomes a Derived.
};

void pointerConversion5(BaseAndDerivedInverter BADI, Derived D) { pointerConversion5(D, BADI); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion5' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:48: note: the first parameter in the range is 'BADI'
// CHECK-MESSAGES: :[[@LINE-3]]:62: note: the last parameter in the range is 'D'
// CHECK-MESSAGES: :[[@LINE-4]]:54: note: 'BaseAndDerivedInverter' and 'Derived' may be implicitly converted: 'BaseAndDerivedInverter' -> 'Derived', 'Derived' -> 'Base' -> 'BaseAndDerivedInverter'
// CHECK-MESSAGES: :[[@LINE-8]]:3: note: the implicit conversion involves the conversion operator declared here
// CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the converting constructor declared here

void pointerConversion6(void (*NTF)() noexcept, void (*TF)()) {}
// NO-WARN: This call cannot be swapped, even if "getCanonicalType()" believes otherwise.

using NonThrowingFunction = void (*)() noexcept;

struct NoexceptMaker {
  NoexceptMaker(void (*ThrowingFunction)());
  // Need to use a typedef here because
  // "conversion function cannot convert to a function type".
  // operator (void (*)() noexcept) () const;
  operator NonThrowingFunction() const;
};

void pointerConversion7(void (*NTF)() noexcept, NoexceptMaker NM) { pointerConversion7(NM, NTF); }
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion7' of convertible types
// CHECK-MESSAGES: :[[@LINE-2]]:32: note: the first parameter in the range is 'NTF'
// CHECK-MESSAGES: :[[@LINE-3]]:63: note: the last parameter in the range is 'NM'
// CHECK-MESSAGES: :[[@LINE-4]]:49: note: 'void (*)() noexcept' and 'NoexceptMaker' may be implicitly converted: 'void (*)() noexcept' -> 'void (*)()' -> 'NoexceptMaker', 'NoexceptMaker' -> 'NonThrowingFunction' -> 'void (*)() noexcept'
// CHECK-MESSAGES: :[[@LINE-12]]:3: note: the implicit conversion involves the converting constructor declared here
// CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here

struct ToType;
struct MiddleStep1 {
  operator ToType() const;
};
struct FromType {
  operator MiddleStep1() const;
};
struct MiddleStep2 {
  operator FromType() const;
};
struct ToType {
  operator MiddleStep2() const;
};

void f(FromType F, ToType T) { // NO-WARN: The path takes two steps.
  MiddleStep2 MS2 = T;
  FromType F2 = MS2;

  MiddleStep1 MS1 = F;
  ToType T2 = MS1;

  f(F2, T2);
}

// Synthesised example from OpenCV.
template <typename T>
struct TemplateConversion {
  template <typename T2>
  operator TemplateConversion<T2>() const;
};
using IntConverter = TemplateConversion<int>;
using FloatConverter = TemplateConversion<float>;

void templateConversion(IntConverter IC, FloatConverter FC) { templateConversion(FC, IC); }
// Note: even though this swap is possible, we do not model things when it comes to "template magic".
// But at least the check should not crash!