SignedBitwiseCheck.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //===--- SignedBitwiseCheck.cpp - clang-tidy-------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "SignedBitwiseCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. using namespace clang::ast_matchers;
  12. using namespace clang::ast_matchers::internal;
  13. namespace clang::tidy::hicpp {
  14. SignedBitwiseCheck::SignedBitwiseCheck(StringRef Name,
  15. ClangTidyContext *Context)
  16. : ClangTidyCheck(Name, Context),
  17. IgnorePositiveIntegerLiterals(
  18. Options.get("IgnorePositiveIntegerLiterals", false)) {}
  19. void SignedBitwiseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
  20. Options.store(Opts, "IgnorePositiveIntegerLiterals",
  21. IgnorePositiveIntegerLiterals);
  22. }
  23. void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
  24. const auto SignedIntegerOperand =
  25. (IgnorePositiveIntegerLiterals
  26. ? expr(ignoringImpCasts(hasType(isSignedInteger())),
  27. unless(integerLiteral()))
  28. : expr(ignoringImpCasts(hasType(isSignedInteger()))))
  29. .bind("signed-operand");
  30. // The standard [bitmask.types] allows some integral types to be implemented
  31. // as signed types. Exclude these types from diagnosing for bitwise or(|) and
  32. // bitwise and(&). Shifting and complementing such values is still not
  33. // allowed.
  34. const auto BitmaskType = namedDecl(
  35. hasAnyName("::std::locale::category", "::std::ctype_base::mask",
  36. "::std::ios_base::fmtflags", "::std::ios_base::iostate",
  37. "::std::ios_base::openmode"));
  38. const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));
  39. // Match binary bitwise operations on signed integer arguments.
  40. Finder->addMatcher(
  41. binaryOperator(hasAnyOperatorName("^", "|", "&", "^=", "|=", "&="),
  42. unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),
  43. hasEitherOperand(SignedIntegerOperand),
  44. hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
  45. .bind("binary-no-sign-interference"),
  46. this);
  47. // Shifting and complement is not allowed for any signed integer type because
  48. // the sign bit may corrupt the result.
  49. Finder->addMatcher(
  50. binaryOperator(hasAnyOperatorName("<<", ">>", "<<=", ">>="),
  51. hasEitherOperand(SignedIntegerOperand),
  52. hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
  53. .bind("binary-sign-interference"),
  54. this);
  55. // Match unary operations on signed integer types.
  56. Finder->addMatcher(
  57. unaryOperator(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))
  58. .bind("unary-signed"),
  59. this);
  60. }
  61. void SignedBitwiseCheck::check(const MatchFinder::MatchResult &Result) {
  62. const ast_matchers::BoundNodes &N = Result.Nodes;
  63. const auto *SignedOperand = N.getNodeAs<Expr>("signed-operand");
  64. assert(SignedOperand &&
  65. "No signed operand found in problematic bitwise operations");
  66. bool IsUnary = false;
  67. SourceLocation OperatorLoc;
  68. if (const auto *UnaryOp = N.getNodeAs<UnaryOperator>("unary-signed")) {
  69. IsUnary = true;
  70. OperatorLoc = UnaryOp->getOperatorLoc();
  71. } else {
  72. if (const auto *BinaryOp =
  73. N.getNodeAs<BinaryOperator>("binary-no-sign-interference"))
  74. OperatorLoc = BinaryOp->getOperatorLoc();
  75. else if (const auto *BinaryOp =
  76. N.getNodeAs<BinaryOperator>("binary-sign-interference"))
  77. OperatorLoc = BinaryOp->getOperatorLoc();
  78. else
  79. llvm_unreachable("unexpected matcher result");
  80. }
  81. diag(SignedOperand->getBeginLoc(), "use of a signed integer operand with a "
  82. "%select{binary|unary}0 bitwise operator")
  83. << IsUnary << SignedOperand->getSourceRange() << OperatorLoc;
  84. }
  85. } // namespace clang::tidy::hicpp