xbolva00 updated this revision to Diff 205121.
xbolva00 added a comment.

Fixed notes by @jfb. Thank you.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63423/new/

https://reviews.llvm.org/D63423

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExpr.cpp
  test/Sema/warn-xor-as-pow.c
  test/SemaCXX/warn-xor-as-pow.cpp

Index: test/SemaCXX/warn-xor-as-pow.cpp
===================================================================
--- test/SemaCXX/warn-xor-as-pow.cpp
+++ test/SemaCXX/warn-xor-as-pow.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wxor-as-pow %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+#define XOR(x, y) (x ^ y)
+#define TWO 2
+#define TEN 10
+#define TWO_ULL 2ULL
+
+void test(unsigned a, unsigned b) {
+  unsigned res;
+  res = a ^ 5;
+  res = 2 ^ b;
+  res = a ^ b;
+  res = 2 ^ 0; // expected-warning {{result of '2 ^ 0' is 2, maybe you mean '1<<0' (1)?}}
+               // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1"
+               // expected-note@-2 {{replace expression with '(2) ^ 0' to silence this warning}}
+  res = 2 ^ 1; // expected-warning {{result of '2 ^ 1' is 3, maybe you mean '1<<1' (2)?}}
+               // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<1"
+               // expected-note@-2 {{replace expression with '(2) ^ 1' to silence this warning}}
+  res = 2 ^ 2; // expected-warning {{result of '2 ^ 2' is 0, maybe you mean '1<<2' (4)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<2"
+  // expected-note@-2 {{replace expression with '(2) ^ 2' to silence this warning}}
+  res = 2 ^ 8; // expected-warning {{result of '2 ^ 8' is 10, maybe you mean '1<<8' (256)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<8"
+  // expected-note@-2 {{replace expression with '(2) ^ 8' to silence this warning}}
+  res = TWO ^ 8; // expected-warning {{result of 'TWO ^ 8' is 10, maybe you mean '1<<8' (256)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"1<<8"
+  // expected-note@-2 {{replace expression with '(TWO) ^ 8' to silence this warning}}
+  res = 2 ^ 16; // expected-warning {{result of '2 ^ 16' is 18, maybe you mean '1<<16' (65536)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"1<<16"
+  // expected-note@-2 {{replace expression with '(2) ^ 16' to silence this warning}}
+  res = 2 ^ TEN; // expected-warning {{result of '2 ^ TEN' is 8, maybe you mean '1<<TEN' (1024)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"1<<TEN"
+  // expected-note@-2 {{replace expression with '(2) ^ TEN' to silence this warning}}
+  res = (2) ^ 16;
+  res = 2 xor 16;
+  res = 0b10 ^ 16;
+  res = 2 ^ 0b100;
+  res = XOR(2, 16);
+  unsigned char two = 2;
+  res = two ^ 16;
+  res = TWO_ULL ^ 16;
+  res = 2 ^ 32; // expected-warning {{result of '2 ^ 32' is 34; maybe you mean '1<<32', but shift count >= width of type}}
+  // expected-note@-1 {{replace expression with '(2) ^ 32' to silence this warning}}
+  res = 2 ^ 64; // expected-warning {{result of '2 ^ 64' is 66; maybe you mean '1<<64', but shift count >= width of type}}
+  // expected-note@-1 {{replace expression with '(2) ^ 64' to silence this warning}}
+
+  res = 10 ^ 0;
+  res = 10 ^ 1; // expected-warning {{result of '10 ^ 1' is 11, maybe you mean '10'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"10"
+  // expected-note@-2 {{replace expression with '(10) ^ 1' to silence this warning}}
+  res = 10 ^ 2; // expected-warning {{result of '10 ^ 2' is 8, maybe you mean '100'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"100"
+  // expected-note@-2 {{replace expression with '(10) ^ 2' to silence this warning}}
+  res = 10 ^ 4; // expected-warning {{result of '10 ^ 4' is 14, maybe you mean '10000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"10000"
+  // expected-note@-2 {{replace expression with '(10) ^ 4' to silence this warning}}
+  res = 10 ^ 10; // expected-warning {{result of '10 ^ 10' is 0, maybe you mean '10000000000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"10000000000"
+  // expected-note@-2 {{replace expression with '(10) ^ 10' to silence this warning}}
+  res = TEN ^ 10; // expected-warning {{result of 'TEN ^ 10' is 0, maybe you mean '10000000000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:17}:"10000000000"
+  // expected-note@-2 {{replace expression with '(TEN) ^ 10' to silence this warning}}
+  res = (10) ^ 10;
+  res = 10 xor 10;
+  res = XOR(10, 10);
+}
Index: test/Sema/warn-xor-as-pow.c
===================================================================
--- test/Sema/warn-xor-as-pow.c
+++ test/Sema/warn-xor-as-pow.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wxor-as-pow %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+#define XOR(x, y) (x ^ y)
+#define TWO 2
+#define TEN 10
+#define TWO_ULL 2ULL
+
+void test(unsigned a, unsigned b) {
+  unsigned res;
+  res = a ^ 5;
+  res = 2 ^ b;
+  res = a ^ b;
+  res = 2 ^ 0; // expected-warning {{result of '2 ^ 0' is 2, maybe you mean '1<<0' (1)?}}
+               // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1"
+               // expected-note@-2 {{replace expression with '(2) ^ 0' to silence this warning}}
+  res = 2 ^ 1; // expected-warning {{result of '2 ^ 1' is 3, maybe you mean '1<<1' (2)?}}
+               // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<1"
+               // expected-note@-2 {{replace expression with '(2) ^ 1' to silence this warning}}
+  res = 2 ^ 2; // expected-warning {{result of '2 ^ 2' is 0, maybe you mean '1<<2' (4)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<2"
+  // expected-note@-2 {{replace expression with '(2) ^ 2' to silence this warning}}
+  res = 2 ^ 8; // expected-warning {{result of '2 ^ 8' is 10, maybe you mean '1<<8' (256)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"1<<8"
+  // expected-note@-2 {{replace expression with '(2) ^ 8' to silence this warning}}
+  res = TWO ^ 8; // expected-warning {{result of 'TWO ^ 8' is 10, maybe you mean '1<<8' (256)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"1<<8"
+  // expected-note@-2 {{replace expression with '(TWO) ^ 8' to silence this warning}}
+  res = 2 ^ 16; // expected-warning {{result of '2 ^ 16' is 18, maybe you mean '1<<16' (65536)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"1<<16"
+  // expected-note@-2 {{replace expression with '(2) ^ 16' to silence this warning}}
+  res = 2 ^ TEN; // expected-warning {{result of '2 ^ TEN' is 8, maybe you mean '1<<TEN' (1024)?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"1<<TEN"
+  // expected-note@-2 {{replace expression with '(2) ^ TEN' to silence this warning}}
+  res = (2) ^ 16;
+  res = 0b10 ^ 16;
+  res = 2 ^ 0b100;
+  res = XOR(2, 16);
+  unsigned char two = 2;
+  res = two ^ 16;
+  res = TWO_ULL ^ 16;
+  res = 2 ^ 32; // expected-warning {{result of '2 ^ 32' is 34; maybe you mean '1<<32', but shift count >= width of type}}
+  // expected-note@-1 {{replace expression with '(2) ^ 32' to silence this warning}}
+  res = 2 ^ 64; // expected-warning {{result of '2 ^ 64' is 66; maybe you mean '1<<64', but shift count >= width of type}}
+  // expected-note@-1 {{replace expression with '(2) ^ 64' to silence this warning}}
+
+  res = 10 ^ 0;
+  res = 10 ^ 1; // expected-warning {{result of '10 ^ 1' is 11, maybe you mean '10'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"10"
+  // expected-note@-2 {{replace expression with '(10) ^ 1' to silence this warning}}
+  res = 10 ^ 2; // expected-warning {{result of '10 ^ 2' is 8, maybe you mean '100'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"100"
+  // expected-note@-2 {{replace expression with '(10) ^ 2' to silence this warning}}
+  res = 10 ^ 4; // expected-warning {{result of '10 ^ 4' is 14, maybe you mean '10000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:15}:"10000"
+  // expected-note@-2 {{replace expression with '(10) ^ 4' to silence this warning}}
+  res = 10 ^ 10; // expected-warning {{result of '10 ^ 10' is 0, maybe you mean '10000000000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:16}:"10000000000"
+  // expected-note@-2 {{replace expression with '(10) ^ 10' to silence this warning}}
+  res = TEN ^ 10; // expected-warning {{result of 'TEN ^ 10' is 0, maybe you mean '10000000000'?}}
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:17}:"10000000000"
+  // expected-note@-2 {{replace expression with '(TEN) ^ 10' to silence this warning}}
+  res = (10) ^ 10;
+  res = XOR(10, 10);
+}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -10890,6 +10890,76 @@
   return GetSignedVectorType(vType);
 }
 
+static void diagnoseXorMisusedAsPow(Sema &S, ExprResult &LHS, ExprResult &RHS,
+                                    SourceLocation Loc) {
+  // Do not diagnose macros
+  if (Loc.isMacroID())
+    return;
+
+  auto *LHSInt = dyn_cast<IntegerLiteral>(LHS.get());
+  auto *RHSInt = dyn_cast<IntegerLiteral>(RHS.get());
+  if (!LHSInt || !RHSInt)
+    return;
+  if (LHSInt->getValue().getBitWidth() != RHSInt->getValue().getBitWidth())
+    return;
+
+  CharSourceRange OpRange = CharSourceRange::getCharRange(
+      LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation()));
+  llvm::StringRef ExprStr =
+      Lexer::getSourceText(OpRange, S.getSourceManager(), S.getLangOpts());
+
+  // Do not diagnose binary literals
+  if (ExprStr.find("0b") != llvm::StringRef::npos)
+    return;
+  if (S.getLangOpts().CPlusPlus) {
+    // Do not diagnose if xor keyword is used
+    if (ExprStr.find("xor") != llvm::StringRef::npos)
+      return;
+  }
+
+  const llvm::APInt &LeftSideValue = LHSInt->getValue();
+  const llvm::APInt &RightSideValue = RHSInt->getValue();
+  const int64_t RightSideIntValue = RightSideValue.getSExtValue();
+
+  if (LeftSideValue == 2 || LeftSideValue == 10) {
+    llvm::APInt XorValue = LeftSideValue ^ RightSideValue;
+    std::string LHSStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(LHSInt->getSourceRange()),
+        S.getSourceManager(), S.getLangOpts());
+    std::string RHSStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(RHSInt->getSourceRange()),
+        S.getSourceManager(), S.getLangOpts());
+    if (LeftSideValue == 2 && RightSideIntValue >= 0) {
+      std::string SuggestedExpr = "1<<" + RHSStr;
+      bool Overflow = false;
+      llvm::APInt One = (LeftSideValue - 1);
+      llvm::APInt PowValue = One.ushl_ov(RightSideValue, Overflow);
+      if (Overflow) {
+        S.Diag(Loc, diag::warn_xor_used_as_pow_shift_count_overflow)
+            << ExprStr << XorValue.toString(10, true) << SuggestedExpr;
+      } else {
+        S.Diag(Loc, diag::warn_xor_used_as_pow_base_two)
+            << ExprStr << XorValue.toString(10, true) << SuggestedExpr
+            << PowValue.toString(10, true)
+            << FixItHint::CreateReplacement(
+                   OpRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr);
+      }
+    } else if (LeftSideValue == 10 && RightSideIntValue > 0) {
+      std::string SuggestedValue = "1" + std::string(RightSideIntValue, '0');
+      S.Diag(Loc, diag::warn_xor_used_as_pow_base_ten)
+          << ExprStr << XorValue.toString(10, true) << SuggestedValue
+          << FixItHint::CreateReplacement(
+                 OpRange, (RightSideIntValue == 0) ? "10" : SuggestedValue);
+    } else {
+      // Nothing was diagnosed
+      return;
+    }
+
+    S.Diag(Loc, diag::note_xor_used_as_pow_silence)
+        << ("(" + LHSStr + ") ^ " + RHSStr);
+  }
+}
+
 QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
                                           SourceLocation Loc) {
   // Ensure that either both operands are of the same vector type, or
@@ -10933,6 +11003,9 @@
   if (Opc == BO_And)
     diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
 
+  if (Opc == BO_Xor)
+    diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc);
+
   ExprResult LHSResult = LHS, RHSResult = RHS;
   QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
                                                  IsCompAssign);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3302,6 +3302,18 @@
   "code; pointer may be assumed to always convert to true">,
   InGroup<UndefinedBoolConversion>;
 
+def warn_xor_used_as_pow_base_two : Warning<
+  "result of '%0' is %1, maybe you mean '%2' (%3)?">,
+  InGroup<XorAsPow>;
+def warn_xor_used_as_pow_shift_count_overflow : Warning<
+  "result of '%0' is %1; maybe you mean '%2', but shift count >= width of type">,
+  InGroup<XorAsPow>;
+def warn_xor_used_as_pow_base_ten : Warning<
+  "result of '%0' is %1, maybe you mean '%2'?">,
+  InGroup<XorAsPow>;
+def note_xor_used_as_pow_silence : Note<
+  "replace expression with '%0' to silence this warning">;
+
 def warn_null_pointer_compare : Warning<
     "comparison of %select{address of|function|array}0 '%1' %select{not |}2"
     "equal to a null pointer is always %select{true|false}2">,
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -505,6 +505,7 @@
 def GNUUnionCast : DiagGroup<"gnu-union-cast">;
 def GNUVariableSizedTypeNotAtEnd : DiagGroup<"gnu-variable-sized-type-not-at-end">;
 def Varargs : DiagGroup<"varargs">;
+def XorAsPow : DiagGroup<"xor-as-pow">;
 
 def Unsequenced : DiagGroup<"unsequenced">;
 // GCC name for -Wunsequenced
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to