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