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!
|