[clang-tidy] 'implicit cast' -> 'implicit conversion'

Summary:
This patch renames checks, check options and changes messages to use correct
term "implicit conversion" instead of "implicit cast" (which has been in use in
Clang AST since ~10 years, but it's still technically incorrect w.r.t. C++
standard).

  * performance-implicit-cast-in-loop -> performance-implicit-conversion-in-loop
  * readability-implicit-bool-cast -> readability-implicit-bool-conversion
    - readability-implicit-bool-cast.AllowConditionalIntegerCasts ->
      readability-implicit-bool-conversion.AllowIntegerConditions
    - readability-implicit-bool-cast.AllowConditionalPointerCasts ->
      readability-implicit-bool-conversion.AllowPointerConditions

Reviewers: hokein, jdennett

Reviewed By: hokein

Subscribers: mgorny, JDevlieghere, xazax.hun, cfe-commits

Differential Revision: https://reviews.llvm.org/D36456

llvm-svn: 310366
diff --git a/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp b/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp
new file mode 100644
index 0000000..0bdd670
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp
@@ -0,0 +1,439 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t
+
+// We need NULL macro, but some buildbots don't like including <cstddef> header
+// This is a portable way of getting it to work
+#undef NULL
+#define NULL 0L
+
+template<typename T>
+void functionTaking(T);
+
+struct Struct {
+  int member;
+};
+
+
+////////// Implicit conversion from bool.
+
+void implicitConversionFromBoolSimpleCases() {
+  bool boolean = true;
+
+  functionTaking<bool>(boolean);
+
+  functionTaking<int>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int' [readability-implicit-bool-conversion]
+  // CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean));
+
+  functionTaking<unsigned long>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
+  // CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean));
+
+  functionTaking<char>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'char'
+  // CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean));
+
+  functionTaking<float>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
+  // CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean));
+
+  functionTaking<double>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
+  // CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean));
+}
+
+float implicitConversionFromBoolInReturnValue() {
+  bool boolean = false;
+  return boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion bool -> 'float'
+  // CHECK-FIXES: return static_cast<float>(boolean);
+}
+
+void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
+  bool boolean = true;
+  boolean = b1 ^ b2;
+  boolean = b1 && b2;
+  boolean |= !b1 || !b2;
+  boolean &= b1;
+  boolean = b1 == true;
+  boolean = b2 != false;
+
+  int integer = boolean - 3;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
+  // CHECK-FIXES: int integer = static_cast<int>(boolean) - 3;
+
+  float floating = boolean / 0.3f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
+  // CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f;
+
+  char character = boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'char'
+  // CHECK-FIXES: char character = static_cast<char>(boolean);
+}
+
+void implicitConversionFromBoollInComplexBoolExpressions() {
+  bool boolean = true;
+  bool anotherBoolean = false;
+
+  int integer = boolean && anotherBoolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
+  // CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean);
+
+  unsigned long unsignedLong = (! boolean) + 4ul;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion bool -> 'unsigned long'
+  // CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul;
+
+  float floating = (boolean || anotherBoolean) * 0.3f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
+  // CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f;
+
+  double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion bool -> 'double'
+  // CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3;
+}
+
+void implicitConversionFromBoolLiterals() {
+  functionTaking<int>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int'
+  // CHECK-FIXES: functionTaking<int>(1);
+
+  functionTaking<unsigned long>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
+  // CHECK-FIXES: functionTaking<unsigned long>(0u);
+
+  functionTaking<signed char>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit conversion bool -> 'signed char'
+  // CHECK-FIXES: functionTaking<signed char>(1);
+
+  functionTaking<float>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
+  // CHECK-FIXES: functionTaking<float>(0.0f);
+
+  functionTaking<double>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
+  // CHECK-FIXES: functionTaking<double>(1.0);
+}
+
+void implicitConversionFromBoolInComparisons() {
+  bool boolean = true;
+  int integer = 0;
+
+  functionTaking<bool>(boolean == integer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int'
+  // CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer);
+
+  functionTaking<bool>(integer != boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit conversion bool -> 'int'
+  // CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean));
+}
+
+void ignoreBoolComparisons() {
+  bool boolean = true;
+  bool anotherBoolean = false;
+
+  functionTaking<bool>(boolean == anotherBoolean);
+  functionTaking<bool>(boolean != anotherBoolean);
+}
+
+void ignoreExplicitCastsFromBool() {
+  bool boolean = true;
+
+  int integer = static_cast<int>(boolean) + 3;
+  float floating = static_cast<float>(boolean) * 0.3f;
+  char character = static_cast<char>(boolean);
+}
+
+void ignoreImplicitConversionFromBoolInMacroExpansions() {
+  bool boolean = true;
+
+  #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
+  int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;
+
+  #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
+  int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
+}
+
+namespace ignoreImplicitConversionFromBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+  bool boolean = true;
+  T uknownType = boolean + 3;
+}
+
+void useOfTemplateFunction() {
+  templateFunction<int>();
+}
+
+} // namespace ignoreImplicitConversionFromBoolInTemplateInstantiations
+
+////////// Implicit conversions to bool.
+
+void implicitConversionToBoolSimpleCases() {
+  int integer = 10;
+  functionTaking<bool>(integer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(integer != 0);
+
+  unsigned long unsignedLong = 10;
+  functionTaking<bool>(unsignedLong);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
+
+  float floating = 0.0f;
+  functionTaking<bool>(floating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
+
+  double doubleFloating = 1.0f;
+  functionTaking<bool>(doubleFloating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0);
+
+  signed char character = 'a';
+  functionTaking<bool>(character);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(character != 0);
+
+  int* pointer = nullptr;
+  functionTaking<bool>(pointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
+
+  auto pointerToMember = &Struct::member;
+  functionTaking<bool>(pointerToMember);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
+  // CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr);
+}
+
+void implicitConversionToBoolInSingleExpressions() {
+  int integer = 10;
+  bool boolComingFromInt = integer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromInt = integer != 0;
+
+  float floating = 10.0f;
+  bool boolComingFromFloat = floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
+
+  signed char character = 'a';
+  bool boolComingFromChar = character;
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit conversion 'signed char' -> bool
+  // CHECK-FIXES: bool boolComingFromChar = character != 0;
+
+  int* pointer = nullptr;
+  bool boolComingFromPointer = pointer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int *' -> bool
+  // CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr;
+}
+
+void implicitConversionToBoolInComplexExpressions() {
+  bool boolean = true;
+
+  int integer = 10;
+  int anotherInteger = 20;
+  bool boolComingFromInteger = integer + anotherInteger;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0;
+
+  float floating = 0.2f;
+  bool boolComingFromFloating = floating - 0.3f || boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
+
+  double doubleFloating = 0.3;
+  bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'double' -> bool
+  // CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean;
+}
+
+void implicitConversionInNegationExpressions() {
+  int integer = 10;
+  bool boolComingFromNegatedInt = !integer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0;
+
+  float floating = 10.0f;
+  bool boolComingFromNegatedFloat = ! floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
+
+  signed char character = 'a';
+  bool boolComingFromNegatedChar = (! character);
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'signed char' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0);
+
+  int* pointer = nullptr;
+  bool boolComingFromNegatedPointer = not pointer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit conversion 'int *' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr;
+}
+
+void implicitConversionToBoolInControlStatements() {
+  int integer = 10;
+  if (integer) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: if (integer != 0) {}
+
+  long int longInteger = 0.2f;
+  for (;longInteger;) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'long' -> bool
+  // CHECK-FIXES: for (;longInteger != 0;) {}
+
+  float floating = 0.3f;
+  while (floating) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: while (floating != 0.0f) {}
+
+  double doubleFloating = 0.4;
+  do {} while (doubleFloating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit conversion 'double' -> bool
+  // CHECK-FIXES: do {} while (doubleFloating != 0.0);
+}
+
+bool implicitConversionToBoolInReturnValue() {
+  float floating = 1.0f;
+  return floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: return floating != 0.0f;
+}
+
+void implicitConversionToBoolFromLiterals() {
+  functionTaking<bool>(0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>(1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(2ul);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>(0.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>(1.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(2.0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>('\0');
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>('a');
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>("");
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>("abc");
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(NULL);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+}
+
+void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
+  functionTaking<bool>(-0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0) != 0);
+
+  functionTaking<bool>(-0.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
+
+  functionTaking<bool>(-0.0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0);
+}
+
+void implicitConversionToBoolInWithOverloadedOperators() {
+  struct UserStruct {
+    int operator()(int x) { return x; }
+    int operator+(int y) { return y; }
+  };
+
+  UserStruct s;
+
+  functionTaking<bool>(s(0));
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(s(0) != 0);
+
+  functionTaking<bool>(s + 2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>((s + 2) != 0);
+}
+
+int functionReturningInt();
+int* functionReturningPointer();
+
+void ignoreImplicitConversionToBoolWhenDeclaringVariableInControlStatements() {
+  if (int integer = functionReturningInt()) {}
+
+  while (int* pointer = functionReturningPointer()) {}
+}
+
+void ignoreExplicitCastsToBool() {
+  int integer = 10;
+  bool boolComingFromInt = static_cast<bool>(integer);
+
+  float floating = 10.0f;
+  bool boolComingFromFloat = static_cast<bool>(floating);
+
+  char character = 'a';
+  bool boolComingFromChar = static_cast<bool>(character);
+
+  int* pointer = nullptr;
+  bool booleanComingFromPointer = static_cast<bool>(pointer);
+}
+
+void ignoreImplicitConversionToBoolInMacroExpansions() {
+  int integer = 3;
+
+  #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
+  bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;
+
+  #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
+  bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
+}
+
+namespace ignoreImplicitConversionToBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+  T unknownType = 0;
+  bool boolean = unknownType;
+}
+
+void useOfTemplateFunction() {
+  templateFunction<int>();
+}
+
+} // namespace ignoreImplicitConversionToBoolInTemplateInstantiations
+
+namespace ignoreUserDefinedConversionOperator {
+
+struct StructWithUserConversion {
+  operator bool();
+};
+
+void useOfUserConversion() {
+  StructWithUserConversion structure;
+  functionTaking<bool>(structure);
+}
+
+} // namespace ignoreUserDefinedConversionOperator