clang-tools  9.0.0
SignedBitwiseCheck.cpp
Go to the documentation of this file.
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 
9 #include "SignedBitwiseCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 
13 using namespace clang::ast_matchers;
14 using namespace clang::ast_matchers::internal;
15 
16 namespace clang {
17 namespace tidy {
18 namespace hicpp {
19 
20 void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
21  const auto SignedIntegerOperand =
22  expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand");
23 
24  // The standard [bitmask.types] allows some integral types to be implemented
25  // as signed types. Exclude these types from diagnosing for bitwise or(|) and
26  // bitwise and(&). Shifting and complementing such values is still not
27  // allowed.
28  const auto BitmaskType = namedDecl(
29  hasAnyName("::std::locale::category", "::std::ctype_base::mask",
30  "::std::ios_base::fmtflags", "::std::ios_base::iostate",
31  "::std::ios_base::openmode"));
32  const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));
33 
34  // Match binary bitwise operations on signed integer arguments.
35  Finder->addMatcher(
36  binaryOperator(anyOf(hasOperatorName("^"), hasOperatorName("|"),
37  hasOperatorName("&"), hasOperatorName("^="),
38  hasOperatorName("|="), hasOperatorName("&=")),
39 
40  unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),
41 
42  hasEitherOperand(SignedIntegerOperand),
43  hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
44  .bind("binary-no-sign-interference"),
45  this);
46 
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(anyOf(hasOperatorName("<<"), hasOperatorName(">>"),
51  hasOperatorName("<<="), hasOperatorName(">>=")),
52  hasEitherOperand(SignedIntegerOperand),
53  hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
54  .bind("binary-sign-interference"),
55  this);
56 
57  // Match unary operations on signed integer types.
58  Finder->addMatcher(
59  unaryOperator(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))
60  .bind("unary-signed"),
61  this);
62 }
63 
64 void SignedBitwiseCheck::check(const MatchFinder::MatchResult &Result) {
65  const ast_matchers::BoundNodes &N = Result.Nodes;
66  const auto *SignedOperand = N.getNodeAs<Expr>("signed-operand");
67  assert(SignedOperand &&
68  "No signed operand found in problematic bitwise operations");
69 
70  bool IsUnary = false;
71  SourceLocation Location;
72 
73  if (const auto *UnaryOp = N.getNodeAs<UnaryOperator>("unary-signed")) {
74  IsUnary = true;
75  Location = UnaryOp->getBeginLoc();
76  } else {
77  if (const auto *BinaryOp =
78  N.getNodeAs<BinaryOperator>("binary-no-sign-interference"))
79  Location = BinaryOp->getBeginLoc();
80  else if (const auto *BinaryOp =
81  N.getNodeAs<BinaryOperator>("binary-sign-interference"))
82  Location = BinaryOp->getBeginLoc();
83  else
84  llvm_unreachable("unexpected matcher result");
85  }
86  diag(Location, "use of a signed integer operand with a "
87  "%select{binary|unary}0 bitwise operator")
88  << IsUnary << SignedOperand->getSourceRange();
89 }
90 
91 } // namespace hicpp
92 } // namespace tidy
93 } // namespace clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: Rename.cpp:36