brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.1 KiB · 19c716e Raw
103 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "SignedBitwiseCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/ASTMatchers/ASTMatchers.h"13 14using namespace clang::ast_matchers;15using namespace clang::ast_matchers::internal;16 17namespace clang::tidy::hicpp {18 19SignedBitwiseCheck::SignedBitwiseCheck(StringRef Name,20                                       ClangTidyContext *Context)21    : ClangTidyCheck(Name, Context),22      IgnorePositiveIntegerLiterals(23          Options.get("IgnorePositiveIntegerLiterals", false)) {}24 25void SignedBitwiseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {26  Options.store(Opts, "IgnorePositiveIntegerLiterals",27                IgnorePositiveIntegerLiterals);28}29 30void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {31  const auto SignedIntegerOperand =32      (IgnorePositiveIntegerLiterals33           ? expr(ignoringImpCasts(34                 allOf(hasType(isSignedInteger()), unless(integerLiteral()))))35           : expr(ignoringImpCasts(hasType(isSignedInteger()))))36          .bind("signed-operand");37 38  // The standard [bitmask.types] allows some integral types to be implemented39  // as signed types. Exclude these types from diagnosing for bitwise or(|) and40  // bitwise and(&). Shifting and complementing such values is still not41  // allowed.42  const auto BitmaskType = namedDecl(43      hasAnyName("::std::locale::category", "::std::ctype_base::mask",44                 "::std::ios_base::fmtflags", "::std::ios_base::iostate",45                 "::std::ios_base::openmode"));46  const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));47 48  // Match binary bitwise operations on signed integer arguments.49  Finder->addMatcher(50      binaryOperator(hasAnyOperatorName("^", "|", "&", "^=", "|=", "&="),51 52                     unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),53 54                     hasEitherOperand(SignedIntegerOperand),55                     hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))56          .bind("binary-no-sign-interference"),57      this);58 59  // Shifting and complement is not allowed for any signed integer type because60  // the sign bit may corrupt the result.61  Finder->addMatcher(62      binaryOperator(hasAnyOperatorName("<<", ">>", "<<=", ">>="),63                     hasEitherOperand(SignedIntegerOperand),64                     hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))65          .bind("binary-sign-interference"),66      this);67 68  // Match unary operations on signed integer types.69  Finder->addMatcher(70      unaryOperator(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))71          .bind("unary-signed"),72      this);73}74 75void SignedBitwiseCheck::check(const MatchFinder::MatchResult &Result) {76  const ast_matchers::BoundNodes &N = Result.Nodes;77  const auto *SignedOperand = N.getNodeAs<Expr>("signed-operand");78  assert(SignedOperand &&79         "No signed operand found in problematic bitwise operations");80 81  bool IsUnary = false;82  SourceLocation OperatorLoc;83 84  if (const auto *UnaryOp = N.getNodeAs<UnaryOperator>("unary-signed")) {85    IsUnary = true;86    OperatorLoc = UnaryOp->getOperatorLoc();87  } else {88    if (const auto *BinaryOp =89            N.getNodeAs<BinaryOperator>("binary-no-sign-interference"))90      OperatorLoc = BinaryOp->getOperatorLoc();91    else if (const auto *BinaryOp =92                 N.getNodeAs<BinaryOperator>("binary-sign-interference"))93      OperatorLoc = BinaryOp->getOperatorLoc();94    else95      llvm_unreachable("unexpected matcher result");96  }97  diag(SignedOperand->getBeginLoc(), "use of a signed integer operand with a "98                                     "%select{binary|unary}0 bitwise operator")99      << IsUnary << SignedOperand->getSourceRange() << OperatorLoc;100}101 102} // namespace clang::tidy::hicpp103