clang-tools  4.0.0
RedundantExpressionCheck.cpp
Go to the documentation of this file.
1 //===--- RedundantExpressionCheck.cpp - clang-tidy-------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "../utils/Matchers.h"
12 #include "../utils/OptionsUtils.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Basic/LLVM.h"
16 #include "clang/Basic/SourceLocation.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Lex/Lexer.h"
19 #include "llvm/ADT/APInt.h"
20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/FoldingSet.h"
22 #include "llvm/Support/Casting.h"
23 #include <algorithm>
24 #include <cassert>
25 #include <cstdint>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 using namespace clang::ast_matchers;
31 using namespace clang::tidy::matchers;
32 
33 namespace clang {
34 namespace tidy {
35 namespace misc {
36 
37 namespace {
38 using llvm::APSInt;
39 } // namespace
40 
41 static const char KnownBannedMacroNames[] =
42  "EAGAIN;EWOULDBLOCK;SIGCLD;SIGCHLD;";
43 
44 static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
45  Result = Value;
46  ++Result;
47  return Value < Result;
48 }
49 
50 static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
51  const NestedNameSpecifier *Right) {
52  llvm::FoldingSetNodeID LeftID, RightID;
53  Left->Profile(LeftID);
54  Right->Profile(RightID);
55  return LeftID == RightID;
56 }
57 
58 static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
59  if (!Left || !Right)
60  return !Left && !Right;
61 
62  Left = Left->IgnoreParens();
63  Right = Right->IgnoreParens();
64 
65  // Compare classes.
66  if (Left->getStmtClass() != Right->getStmtClass())
67  return false;
68 
69  // Compare children.
70  Expr::const_child_iterator LeftIter = Left->child_begin();
71  Expr::const_child_iterator RightIter = Right->child_begin();
72  while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
73  if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
74  dyn_cast<Expr>(*RightIter)))
75  return false;
76  ++LeftIter;
77  ++RightIter;
78  }
79  if (LeftIter != Left->child_end() || RightIter != Right->child_end())
80  return false;
81 
82  // Perform extra checks.
83  switch (Left->getStmtClass()) {
84  default:
85  return false;
86 
87  case Stmt::CharacterLiteralClass:
88  return cast<CharacterLiteral>(Left)->getValue() ==
89  cast<CharacterLiteral>(Right)->getValue();
90  case Stmt::IntegerLiteralClass: {
91  llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
92  llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
93  return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
94  LeftLit == RightLit;
95  }
96  case Stmt::FloatingLiteralClass:
97  return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
98  cast<FloatingLiteral>(Right)->getValue());
99  case Stmt::StringLiteralClass:
100  return cast<StringLiteral>(Left)->getBytes() ==
101  cast<StringLiteral>(Right)->getBytes();
102 
103  case Stmt::DependentScopeDeclRefExprClass:
104  if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
105  cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
106  return false;
108  cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
109  cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
110  case Stmt::DeclRefExprClass:
111  return cast<DeclRefExpr>(Left)->getDecl() ==
112  cast<DeclRefExpr>(Right)->getDecl();
113  case Stmt::MemberExprClass:
114  return cast<MemberExpr>(Left)->getMemberDecl() ==
115  cast<MemberExpr>(Right)->getMemberDecl();
116 
117  case Stmt::CStyleCastExprClass:
118  return cast<CStyleCastExpr>(Left)->getTypeAsWritten() ==
119  cast<CStyleCastExpr>(Right)->getTypeAsWritten();
120 
121  case Stmt::CallExprClass:
122  case Stmt::ImplicitCastExprClass:
123  case Stmt::ArraySubscriptExprClass:
124  return true;
125 
126  case Stmt::UnaryOperatorClass:
127  if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
128  return false;
129  return cast<UnaryOperator>(Left)->getOpcode() ==
130  cast<UnaryOperator>(Right)->getOpcode();
131  case Stmt::BinaryOperatorClass:
132  return cast<BinaryOperator>(Left)->getOpcode() ==
133  cast<BinaryOperator>(Right)->getOpcode();
134  }
135 }
136 
137 // For a given expression 'x', returns whether the ranges covered by the
138 // relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5).
139 static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
140  const APSInt &ValueLHS,
141  BinaryOperatorKind OpcodeRHS,
142  const APSInt &ValueRHS) {
143  assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
144  "Values must be ordered");
145  // Handle the case where constants are the same: x <= 4 <==> x <= 4.
146  if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
147  return OpcodeLHS == OpcodeRHS;
148 
149  // Handle the case where constants are off by one: x <= 4 <==> x < 5.
150  APSInt ValueLHS_plus1;
151  return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
152  (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
153  incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
154  APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
155 }
156 
157 // For a given expression 'x', returns whether the ranges covered by the
158 // relational operators are fully disjoint (i.e. x < 4 and x > 7).
159 static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
160  const APSInt &ValueLHS,
161  BinaryOperatorKind OpcodeRHS,
162  const APSInt &ValueRHS) {
163  assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
164  "Values must be ordered");
165 
166  // Handle cases where the constants are the same.
167  if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
168  switch (OpcodeLHS) {
169  case BO_EQ:
170  return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
171  case BO_NE:
172  return OpcodeRHS == BO_EQ;
173  case BO_LE:
174  return OpcodeRHS == BO_GT;
175  case BO_GE:
176  return OpcodeRHS == BO_LT;
177  case BO_LT:
178  return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
179  case BO_GT:
180  return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
181  default:
182  return false;
183  }
184  }
185 
186  // Handle cases where the constants are different.
187  if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
188  (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
189  return true;
190 
191  // Handle the case where constants are off by one: x > 5 && x < 6.
192  APSInt ValueLHS_plus1;
193  if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
194  incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
195  APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
196  return true;
197 
198  return false;
199 }
200 
201 // Returns whether the ranges covered by the union of both relational
202 // expressions covers the whole domain (i.e. x < 10 and x > 0).
203 static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
204  const APSInt &ValueLHS,
205  BinaryOperatorKind OpcodeRHS,
206  const APSInt &ValueRHS) {
207  assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
208  "Values must be ordered");
209 
210  // Handle cases where the constants are the same: x < 5 || x >= 5.
211  if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
212  switch (OpcodeLHS) {
213  case BO_EQ:
214  return OpcodeRHS == BO_NE;
215  case BO_NE:
216  return OpcodeRHS == BO_EQ;
217  case BO_LE:
218  return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
219  case BO_LT:
220  return OpcodeRHS == BO_GE;
221  case BO_GE:
222  return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
223  case BO_GT:
224  return OpcodeRHS == BO_LE;
225  default:
226  return false;
227  }
228  }
229 
230  // Handle the case where constants are off by one: x <= 4 || x >= 5.
231  APSInt ValueLHS_plus1;
232  if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
233  incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
234  APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
235  return true;
236 
237  // Handle cases where the constants are different: x > 4 || x <= 7.
238  if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
239  (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
240  return true;
241 
242  return false;
243 }
244 
245 static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
246  const APSInt &ValueLHS,
247  BinaryOperatorKind OpcodeRHS,
248  const APSInt &ValueRHS) {
249  int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
250  switch (OpcodeLHS) {
251  case BO_EQ:
252  return OpcodeRHS == BO_EQ && Comparison == 0;
253  case BO_NE:
254  return (OpcodeRHS == BO_NE && Comparison == 0) ||
255  (OpcodeRHS == BO_EQ && Comparison != 0) ||
256  (OpcodeRHS == BO_LT && Comparison >= 0) ||
257  (OpcodeRHS == BO_LE && Comparison > 0) ||
258  (OpcodeRHS == BO_GT && Comparison <= 0) ||
259  (OpcodeRHS == BO_GE && Comparison < 0);
260 
261  case BO_LT:
262  return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
263  (OpcodeRHS == BO_LE && Comparison > 0) ||
264  (OpcodeRHS == BO_EQ && Comparison > 0));
265  case BO_GT:
266  return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
267  (OpcodeRHS == BO_GE && Comparison < 0) ||
268  (OpcodeRHS == BO_EQ && Comparison < 0));
269  case BO_LE:
270  return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
271  Comparison >= 0;
272  case BO_GE:
273  return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
274  Comparison <= 0;
275  default:
276  return false;
277  }
278 }
279 
280 static void canonicalNegateExpr(BinaryOperatorKind &Opcode, APSInt &Value) {
281  if (Opcode == BO_Sub) {
282  Opcode = BO_Add;
283  Value = -Value;
284  }
285 }
286 
287 AST_MATCHER(Expr, isIntegerConstantExpr) {
288  if (Node.isInstantiationDependent())
289  return false;
290  return Node.isIntegerConstantExpr(Finder->getASTContext());
291 }
292 
293 // Returns a matcher for integer constant expression.
294 static ast_matchers::internal::Matcher<Expr>
296  std::string CstId = (Id + "-const").str();
297  return expr(isIntegerConstantExpr()).bind(CstId);
298 }
299 
300 // Retrieve the integer value matched by 'matchIntegerConstantExpr' with name
301 // 'Id' and store it into 'Value'.
302 static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
303  StringRef Id, APSInt &Value) {
304  std::string CstId = (Id + "-const").str();
305  const auto *CstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
306  return CstExpr && CstExpr->isIntegerConstantExpr(Value, *Result.Context);
307 }
308 
309 // Returns a matcher for a symbolic expression (any expression except ingeter
310 // constant expression).
311 static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
312  std::string SymId = (Id + "-sym").str();
313  return ignoringParenImpCasts(
314  expr(unless(isIntegerConstantExpr())).bind(SymId));
315 }
316 
317 // Retrieve the expression matched by 'matchSymbolicExpr' with name 'Id' and
318 // store it into 'SymExpr'.
319 static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
320  StringRef Id, const Expr *&SymExpr) {
321  std::string SymId = (Id + "-sym").str();
322  if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
323  SymExpr = Node;
324  return true;
325  }
326  return false;
327 }
328 
329 // Match a binary operator between a symbolic expression and an integer constant
330 // expression.
331 static ast_matchers::internal::Matcher<Expr>
333  const auto BinOpCstExpr =
334  expr(
335  anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"),
336  hasOperatorName("&")),
337  hasEitherOperand(matchSymbolicExpr(Id)),
338  hasEitherOperand(matchIntegerConstantExpr(Id))),
339  binaryOperator(hasOperatorName("-"),
340  hasLHS(matchSymbolicExpr(Id)),
341  hasRHS(matchIntegerConstantExpr(Id)))))
342  .bind(Id);
343  return ignoringParenImpCasts(BinOpCstExpr);
344 }
345 
346 // Retrieve sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
347 // name 'Id'.
348 static bool
349 retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
350  StringRef Id, BinaryOperatorKind &Opcode,
351  const Expr *&Symbol, APSInt &Value) {
352  if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
353  Opcode = BinExpr->getOpcode();
354  return retrieveSymbolicExpr(Result, Id, Symbol) &&
355  retrieveIntegerConstantExpr(Result, Id, Value);
356  }
357  return false;
358 }
359 
360 // Matches relational expression: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
361 static ast_matchers::internal::Matcher<Expr>
363  std::string CastId = (Id + "-cast").str();
364  std::string SwapId = (Id + "-swap").str();
365  std::string NegateId = (Id + "-negate").str();
366 
367  const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
368  isComparisonOperator(), expr().bind(Id),
369  anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
370  hasRHS(matchIntegerConstantExpr(Id))),
371  allOf(hasLHS(matchIntegerConstantExpr(Id)),
372  hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
373 
374  // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
375  // to if (x != 0)).
376  const auto CastExpr =
377  implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
378  hasSourceExpression(matchSymbolicExpr(Id)))
379  .bind(CastId);
380 
381  const auto NegateRelationalExpr =
382  unaryOperator(hasOperatorName("!"),
383  hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
384  .bind(NegateId);
385 
386  const auto NegateNegateRelationalExpr =
387  unaryOperator(hasOperatorName("!"),
388  hasUnaryOperand(unaryOperator(
389  hasOperatorName("!"),
390  hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
391 
392  return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
393  NegateNegateRelationalExpr);
394 }
395 
396 // Retrieve sub-expressions matched by 'matchRelationalIntegerConstantExpr' with
397 // name 'Id'.
398 static bool
399 retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result,
400  StringRef Id, const Expr *&OperandExpr,
401  BinaryOperatorKind &Opcode,
402  const Expr *&Symbol, APSInt &Value) {
403  std::string CastId = (Id + "-cast").str();
404  std::string SwapId = (Id + "-swap").str();
405  std::string NegateId = (Id + "-negate").str();
406 
407  if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
408  // Operand received with explicit comparator.
409  Opcode = Bin->getOpcode();
410  OperandExpr = Bin;
411  if (!retrieveIntegerConstantExpr(Result, Id, Value))
412  return false;
413  } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
414  // Operand received with implicit comparator (cast).
415  Opcode = BO_NE;
416  OperandExpr = Cast;
417  Value = APSInt(32, false);
418  } else {
419  return false;
420  }
421 
422  if (!retrieveSymbolicExpr(Result, Id, Symbol))
423  return false;
424 
425  if (Result.Nodes.getNodeAs<Expr>(SwapId))
426  Opcode = BinaryOperator::reverseComparisonOp(Opcode);
427  if (Result.Nodes.getNodeAs<Expr>(NegateId))
428  Opcode = BinaryOperator::negateComparisonOp(Opcode);
429 
430  return true;
431 }
432 
433 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
434  return areEquivalentExpr(Node.getLHS(), Node.getRHS());
435 }
436 
437 AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
438  return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
439 }
440 
441 AST_MATCHER(CallExpr, parametersAreEquivalent) {
442  return Node.getNumArgs() == 2 &&
443  areEquivalentExpr(Node.getArg(0), Node.getArg(1));
444 }
445 
446 AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
447  return Node.getOperatorLoc().isMacroID();
448 }
449 
450 AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
451  return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
452 }
453 
454 AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
455 
456 AST_MATCHER_P(Expr, expandedByMacro, std::set<std::string>, Names) {
457  const SourceManager &SM = Finder->getASTContext().getSourceManager();
458  const LangOptions &LO = Finder->getASTContext().getLangOpts();
459  SourceLocation Loc = Node.getExprLoc();
460  while (Loc.isMacroID()) {
461  std::string MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
462  if (Names.find(MacroName) != Names.end())
463  return true;
464  Loc = SM.getImmediateMacroCallerLoc(Loc);
465  }
466  return false;
467 }
468 
469 void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
470  const auto AnyLiteralExpr = ignoringParenImpCasts(
471  anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
472 
473  std::vector<std::string> MacroNames =
475  std::set<std::string> Names(MacroNames.begin(), MacroNames.end());
476 
477  const auto BannedIntegerLiteral = integerLiteral(expandedByMacro(Names));
478 
479  Finder->addMatcher(
480  binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
481  hasOperatorName("%"), hasOperatorName("|"),
482  hasOperatorName("&"), hasOperatorName("^"),
483  matchers::isComparisonOperator(),
484  hasOperatorName("&&"), hasOperatorName("||"),
485  hasOperatorName("=")),
486  operandsAreEquivalent(),
487  // Filter noisy false positives.
488  unless(isInTemplateInstantiation()),
489  unless(binaryOperatorIsInMacro()),
490  unless(hasType(realFloatingPointType())),
491  unless(hasEitherOperand(hasType(realFloatingPointType()))),
492  unless(hasLHS(AnyLiteralExpr)),
493  unless(hasDescendant(BannedIntegerLiteral)))
494  .bind("binary"),
495  this);
496 
497  Finder->addMatcher(
498  conditionalOperator(expressionsAreEquivalent(),
499  // Filter noisy false positives.
500  unless(conditionalOperatorIsInMacro()),
501  unless(hasTrueExpression(AnyLiteralExpr)),
502  unless(isInTemplateInstantiation()))
503  .bind("cond"),
504  this);
505 
506  Finder->addMatcher(
507  cxxOperatorCallExpr(
508  anyOf(
509  hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"),
510  hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"),
511  hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"),
512  hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="),
513  hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="),
514  hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="),
515  hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"),
516  hasOverloadedOperatorName("=")),
517  parametersAreEquivalent(),
518  // Filter noisy false positives.
519  unless(isMacro()), unless(isInTemplateInstantiation()))
520  .bind("call"),
521  this);
522 
523  // Match common expressions and apply more checks to find redundant
524  // sub-expressions.
525  // a) Expr <op> K1 == K2
526  // b) Expr <op> K1 == Expr
527  // c) Expr <op> K1 == Expr <op> K2
528  // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
529  const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
530  const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
531  const auto CstRight = matchIntegerConstantExpr("rhs");
532  const auto SymRight = matchSymbolicExpr("rhs");
533 
534  // Match expressions like: x <op> 0xFF == 0xF00.
535  Finder->addMatcher(binaryOperator(isComparisonOperator(),
536  hasEitherOperand(BinOpCstLeft),
537  hasEitherOperand(CstRight))
538  .bind("binop-const-compare-to-const"),
539  this);
540 
541  // Match expressions like: x <op> 0xFF == x.
542  Finder->addMatcher(
543  binaryOperator(isComparisonOperator(),
544  anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
545  allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
546  .bind("binop-const-compare-to-sym"),
547  this);
548 
549  // Match expressions like: x <op> 10 == x <op> 12.
550  Finder->addMatcher(binaryOperator(isComparisonOperator(),
551  hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
552  // Already reported as redundant.
553  unless(operandsAreEquivalent()))
554  .bind("binop-const-compare-to-binop-const"),
555  this);
556 
557  // Match relational expressions combined with logical operators and find
558  // redundant sub-expressions.
559  // see: 'checkRelationalExpr'
560 
561  // Match expressions like: x < 2 && x > 2.
562  const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
563  const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
564  Finder->addMatcher(
565  binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")),
566  hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
567  // Already reported as redundant.
568  unless(operandsAreEquivalent()))
569  .bind("comparisons-of-symbol-and-const"),
570  this);
571 }
572 
573 void RedundantExpressionCheck::checkArithmeticExpr(
574  const MatchFinder::MatchResult &Result) {
575  APSInt LhsValue, RhsValue;
576  const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
577  BinaryOperatorKind LhsOpcode, RhsOpcode;
578 
579  if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
580  "binop-const-compare-to-sym")) {
581  BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
582  if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
583  LhsValue) ||
584  !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
585  !areEquivalentExpr(LhsSymbol, RhsSymbol))
586  return;
587 
588  // Check expressions: x + k == x or x - k == x.
589  if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
590  if ((LhsValue != 0 && Opcode == BO_EQ) ||
591  (LhsValue == 0 && Opcode == BO_NE))
592  diag(ComparisonOperator->getOperatorLoc(),
593  "logical expression is always false");
594  else if ((LhsValue == 0 && Opcode == BO_EQ) ||
595  (LhsValue != 0 && Opcode == BO_NE))
596  diag(ComparisonOperator->getOperatorLoc(),
597  "logical expression is always true");
598  }
599  } else if (const auto *ComparisonOperator =
600  Result.Nodes.getNodeAs<BinaryOperator>(
601  "binop-const-compare-to-binop-const")) {
602  BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
603 
604  if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
605  LhsValue) ||
606  !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
607  RhsValue) ||
608  !areEquivalentExpr(LhsSymbol, RhsSymbol))
609  return;
610 
611  canonicalNegateExpr(LhsOpcode, LhsValue);
612  canonicalNegateExpr(RhsOpcode, RhsValue);
613 
614  // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
615  if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
616  if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
617  (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
618  diag(ComparisonOperator->getOperatorLoc(),
619  "logical expression is always true");
620  } else if ((Opcode == BO_EQ &&
621  APSInt::compareValues(LhsValue, RhsValue) != 0) ||
622  (Opcode == BO_NE &&
623  APSInt::compareValues(LhsValue, RhsValue) == 0)) {
624  diag(ComparisonOperator->getOperatorLoc(),
625  "logical expression is always false");
626  }
627  }
628  }
629 }
630 
631 void RedundantExpressionCheck::checkBitwiseExpr(
632  const MatchFinder::MatchResult &Result) {
633  if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
634  "binop-const-compare-to-const")) {
635  BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
636 
637  APSInt LhsValue, RhsValue;
638  const Expr *LhsSymbol = nullptr;
639  BinaryOperatorKind LhsOpcode;
640  if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
641  LhsValue) ||
642  !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
643  return;
644 
645  uint64_t LhsConstant = LhsValue.getZExtValue();
646  uint64_t RhsConstant = RhsValue.getZExtValue();
647  SourceLocation Loc = ComparisonOperator->getOperatorLoc();
648 
649  // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
650  if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
651  if (Opcode == BO_EQ)
652  diag(Loc, "logical expression is always false");
653  else if (Opcode == BO_NE)
654  diag(Loc, "logical expression is always true");
655  }
656 
657  // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
658  if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
659  if (Opcode == BO_EQ)
660  diag(Loc, "logical expression is always false");
661  else if (Opcode == BO_NE)
662  diag(Loc, "logical expression is always true");
663  }
664  }
665 }
666 
667 void RedundantExpressionCheck::checkRelationalExpr(
668  const MatchFinder::MatchResult &Result) {
669  if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
670  "comparisons-of-symbol-and-const")) {
671  // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
672  BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
673 
674  const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
675  APSInt LhsValue, RhsValue;
676  const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
677  BinaryOperatorKind LhsOpcode, RhsOpcode;
679  Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue) ||
681  Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue) ||
682  !areEquivalentExpr(LhsSymbol, RhsSymbol))
683  return;
684 
685  // Bring to a canonical form: smallest constant must be on the left side.
686  if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
687  std::swap(LhsExpr, RhsExpr);
688  std::swap(LhsValue, RhsValue);
689  std::swap(LhsSymbol, RhsSymbol);
690  std::swap(LhsOpcode, RhsOpcode);
691  }
692 
693  if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
694  areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
695  diag(ComparisonOperator->getOperatorLoc(),
696  "equivalent expression on both side of logical operator");
697  return;
698  }
699 
700  if (Opcode == BO_LAnd) {
701  if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
702  diag(ComparisonOperator->getOperatorLoc(),
703  "logical expression is always false");
704  } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
705  diag(LhsExpr->getExprLoc(), "expression is redundant");
706  } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
707  diag(RhsExpr->getExprLoc(), "expression is redundant");
708  }
709  }
710 
711  if (Opcode == BO_LOr) {
712  if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
713  diag(ComparisonOperator->getOperatorLoc(),
714  "logical expression is always true");
715  } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
716  diag(RhsExpr->getExprLoc(), "expression is redundant");
717  } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
718  diag(LhsExpr->getExprLoc(), "expression is redundant");
719  }
720  }
721  }
722 }
723 
724 void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
725  if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary"))
726  diag(BinOp->getOperatorLoc(), "both side of operator are equivalent");
727  if (const auto *CondOp = Result.Nodes.getNodeAs<ConditionalOperator>("cond"))
728  diag(CondOp->getColonLoc(), "'true' and 'false' expression are equivalent");
729  if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call"))
730  diag(Call->getOperatorLoc(),
731  "both side of overloaded operator are equivalent");
732 
733  checkArithmeticExpr(Result);
734  checkBitwiseExpr(Result);
735  checkRelationalExpr(Result);
736 }
737 
738 } // namespace misc
739 } // namespace tidy
740 } // namespace clang
SourceLocation Loc
'#' location in the include directive
static ast_matchers::internal::Matcher< Expr > matchRelationalIntegerConstantExpr(StringRef Id)
static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:262
static const char KnownBannedMacroNames[]
static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, APSInt &Value)
static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, const NestedNameSpecifier *Right)
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
static bool retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result)
SourceManager & SM
static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static ast_matchers::internal::Matcher< Expr > matchSymbolicExpr(StringRef Id)
static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&SymExpr)
static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
static bool areEquivalentExpr(const Expr *Left, const Expr *Right)
static bool retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
static ast_matchers::internal::Matcher< Expr > matchBinOpIntegerConstantExpr(StringRef Id)
static ast_matchers::internal::Matcher< Expr > matchIntegerConstantExpr(StringRef Id)
static void canonicalNegateExpr(BinaryOperatorKind &Opcode, APSInt &Value)
const NamedDecl * Result
Definition: USRFinder.cpp:162
AST_MATCHER_P(Expr, expandedByMacro, std::set< std::string >, Names)