courbet created this revision.
courbet added reviewers: xazax.hun, alexfh.
Herald added subscribers: cfe-commits, jdoerfert, rnkovacs.
Herald added a project: clang.

Detect a few expressions as likely character expressions, see PR27723.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===================================================================
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===================================================================
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,42 @@
       this);
 }
 
+static bool isLikelyCharExpression(const Expr* Argument, const ASTContext 
&Ctx) {
+  const auto* BinOp = dyn_cast<BinaryOperator>(Argument);
+  if (!BinOp) {
+    return false;
+  }
+  const auto* LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto* RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // <expr> & <mask>, mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+      BinOp->getRHS()->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)) {
+      return true;
+  }
+  // <char literal> + (<expr> % <mod>), where <base> is a char literal.
+  BinOp->dump();
+  llvm::errs() << "A " << isa<CharacterLiteral>(LHS) << " " << 
(BinOp->getOpcode() == BO_Add)<< "\n";
+  if (isa<CharacterLiteral>(LHS) && BinOp->getOpcode() == BO_Add) {
+    const auto* RHSOp = dyn_cast<BinaryOperator>(RHS);
+    llvm::errs() << "B " << RHSOp << " " << (RHSOp ? RHSOp->getOpcode() == 
BO_Rem : false)<< "\n";
+    if (RHSOp && RHSOp->getOpcode() == BO_Rem) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+    return;
+  }
+
   auto Diag =
       diag(Loc, "an integer is interpreted as a character code when assigning "
                 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===================================================================
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===================================================================
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,42 @@
       this);
 }
 
+static bool isLikelyCharExpression(const Expr* Argument, const ASTContext &Ctx) {
+  const auto* BinOp = dyn_cast<BinaryOperator>(Argument);
+  if (!BinOp) {
+    return false;
+  }
+  const auto* LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto* RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // <expr> & <mask>, mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+      BinOp->getRHS()->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)) {
+      return true;
+  }
+  // <char literal> + (<expr> % <mod>), where <base> is a char literal.
+  BinOp->dump();
+  llvm::errs() << "A " << isa<CharacterLiteral>(LHS) << " " << (BinOp->getOpcode() == BO_Add)<< "\n";
+  if (isa<CharacterLiteral>(LHS) && BinOp->getOpcode() == BO_Add) {
+    const auto* RHSOp = dyn_cast<BinaryOperator>(RHS);
+    llvm::errs() << "B " << RHSOp << " " << (RHSOp ? RHSOp->getOpcode() == BO_Rem : false)<< "\n";
+    if (RHSOp && RHSOp->getOpcode() == BO_Rem) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+    return;
+  }
+
   auto Diag =
       diag(Loc, "an integer is interpreted as a character code when assigning "
                 "it to a string; if this is intended, cast the integer to the "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to