clang-tools 6.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
10 #include "RedundantExpressionCheck.h"
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 <cmath>
26 #include <cstdint>
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 llvm::StringSet<> KnownBannedMacroNames = {"EAGAIN", "EWOULDBLOCK",
42 "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 case Stmt::CXXOperatorCallExprClass:
103 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
104 cast<CXXOperatorCallExpr>(Right)->getOperator();
105 case Stmt::DependentScopeDeclRefExprClass:
106 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
107 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
108 return false;
109 return areEquivalentNameSpecifier(
110 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
111 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
112 case Stmt::DeclRefExprClass:
113 return cast<DeclRefExpr>(Left)->getDecl() ==
114 cast<DeclRefExpr>(Right)->getDecl();
115 case Stmt::MemberExprClass:
116 return cast<MemberExpr>(Left)->getMemberDecl() ==
117 cast<MemberExpr>(Right)->getMemberDecl();
118 case Stmt::CXXFunctionalCastExprClass:
119 case Stmt::CStyleCastExprClass:
120 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
121 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
122 case Stmt::CallExprClass:
123 case Stmt::ImplicitCastExprClass:
124 case Stmt::ArraySubscriptExprClass:
125 return true;
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 cover 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 // Handle cases where constants are different but both ops are !=, like:
243 // x != 5 || x != 10
244 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
245 return true;
246
247 return false;
248 }
249
250 static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
251 const APSInt &ValueLHS,
252 BinaryOperatorKind OpcodeRHS,
253 const APSInt &ValueRHS) {
254 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
255 switch (OpcodeLHS) {
256 case BO_EQ:
257 return OpcodeRHS == BO_EQ && Comparison == 0;
258 case BO_NE:
259 return (OpcodeRHS == BO_NE && Comparison == 0) ||
260 (OpcodeRHS == BO_EQ && Comparison != 0) ||
261 (OpcodeRHS == BO_LT && Comparison >= 0) ||
262 (OpcodeRHS == BO_LE && Comparison > 0) ||
263 (OpcodeRHS == BO_GT && Comparison <= 0) ||
264 (OpcodeRHS == BO_GE && Comparison < 0);
265
266 case BO_LT:
267 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
268 (OpcodeRHS == BO_LE && Comparison > 0) ||
269 (OpcodeRHS == BO_EQ && Comparison > 0));
270 case BO_GT:
271 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
272 (OpcodeRHS == BO_GE && Comparison < 0) ||
273 (OpcodeRHS == BO_EQ && Comparison < 0));
274 case BO_LE:
275 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
276 Comparison >= 0;
277 case BO_GE:
278 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
279 Comparison <= 0;
280 default:
281 return false;
282 }
283 }
284
285 static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
286 APSInt &Value) {
287 if (Opcode == BO_Sub) {
288 Opcode = BO_Add;
289 Value = -Value;
290 }
291 }
292
293 AST_MATCHER(Expr, isIntegerConstantExpr) {
294 if (Node.isInstantiationDependent())
295 return false;
296 return Node.isIntegerConstantExpr(Finder->getASTContext());
297 }
298
299 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
300 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
301 }
302
303 AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
304 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
305 }
306
307 AST_MATCHER(CallExpr, parametersAreEquivalent) {
308 return Node.getNumArgs() == 2 &&
309 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
310 }
311
312 AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
313 return Node.getOperatorLoc().isMacroID();
314 }
315
316 AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
317 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
318 }
319
320 AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
321
322 AST_MATCHER_P(Expr, expandedByMacro, llvm::StringSet<>, Names) {
323 const SourceManager &SM = Finder->getASTContext().getSourceManager();
324 const LangOptions &LO = Finder->getASTContext().getLangOpts();
325 SourceLocation Loc = Node.getExprLoc();
326 while (Loc.isMacroID()) {
327 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
328 if (Names.count(MacroName))
329 return true;
330 Loc = SM.getImmediateMacroCallerLoc(Loc);
331 }
332 return false;
333 }
334
335 // Returns a matcher for integer constant expressions.
336 static ast_matchers::internal::Matcher<Expr>
337 matchIntegerConstantExpr(StringRef Id) {
338 std::string CstId = (Id + "-const").str();
339 return expr(isIntegerConstantExpr()).bind(CstId);
340 }
341
342 // Retrieves the integer expression matched by 'matchIntegerConstantExpr' with
343 // name 'Id' and stores it into 'ConstExpr', the value of the expression is
344 // stored into `Value`.
345 static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
346 StringRef Id, APSInt &Value,
347 const Expr *&ConstExpr) {
348 std::string CstId = (Id + "-const").str();
349 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
350 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
351 }
352
353 // Overloaded `retrieveIntegerConstantExpr` for compatibility.
354 static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
355 StringRef Id, APSInt &Value) {
356 const Expr *ConstExpr = nullptr;
357 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
358 }
359
360 // Returns a matcher for symbolic expressions (matches every expression except
361 // ingeter constant expressions).
362 static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
363 std::string SymId = (Id + "-sym").str();
364 return ignoringParenImpCasts(
365 expr(unless(isIntegerConstantExpr())).bind(SymId));
366 }
367
368 // Retrieves the expression matched by 'matchSymbolicExpr' with name 'Id' and
369 // stores it into 'SymExpr'.
370 static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
371 StringRef Id, const Expr *&SymExpr) {
372 std::string SymId = (Id + "-sym").str();
373 if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
374 SymExpr = Node;
375 return true;
376 }
377 return false;
378 }
379
380 // Match a binary operator between a symbolic expression and an integer constant
381 // expression.
382 static ast_matchers::internal::Matcher<Expr>
383 matchBinOpIntegerConstantExpr(StringRef Id) {
384 const auto BinOpCstExpr =
385 expr(
386 anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"),
387 hasOperatorName("&")),
388 hasEitherOperand(matchSymbolicExpr(Id)),
389 hasEitherOperand(matchIntegerConstantExpr(Id))),
390 binaryOperator(hasOperatorName("-"),
391 hasLHS(matchSymbolicExpr(Id)),
392 hasRHS(matchIntegerConstantExpr(Id)))))
393 .bind(Id);
394 return ignoringParenImpCasts(BinOpCstExpr);
395 }
396
397 // Retrieves sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
398 // name 'Id'.
399 static bool
400 retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
401 StringRef Id, BinaryOperatorKind &Opcode,
402 const Expr *&Symbol, APSInt &Value) {
403 if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
404 Opcode = BinExpr->getOpcode();
405 return retrieveSymbolicExpr(Result, Id, Symbol) &&
406 retrieveIntegerConstantExpr(Result, Id, Value);
407 }
408 return false;
409 }
410
411 // Matches relational expressions: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
412 static ast_matchers::internal::Matcher<Expr>
413 matchRelationalIntegerConstantExpr(StringRef Id) {
414 std::string CastId = (Id + "-cast").str();
415 std::string SwapId = (Id + "-swap").str();
416 std::string NegateId = (Id + "-negate").str();
417 std::string OverloadId = (Id + "-overload").str();
418
419 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
420 isComparisonOperator(), expr().bind(Id),
421 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
422 hasRHS(matchIntegerConstantExpr(Id))),
423 allOf(hasLHS(matchIntegerConstantExpr(Id)),
424 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
425
426 // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
427 // to if (x != 0)).
428 const auto CastExpr =
429 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
430 hasSourceExpression(matchSymbolicExpr(Id)))
431 .bind(CastId);
432
433 const auto NegateRelationalExpr =
434 unaryOperator(hasOperatorName("!"),
435 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
436 .bind(NegateId);
437
438 // Do not bind to double negation.
439 const auto NegateNegateRelationalExpr =
440 unaryOperator(hasOperatorName("!"),
441 hasUnaryOperand(unaryOperator(
442 hasOperatorName("!"),
443 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
444
445 const auto OverloadedOperatorExpr =
446 cxxOperatorCallExpr(
447 anyOf(hasOverloadedOperatorName("=="),
448 hasOverloadedOperatorName("!="), hasOverloadedOperatorName("<"),
449 hasOverloadedOperatorName("<="), hasOverloadedOperatorName(">"),
450 hasOverloadedOperatorName(">=")),
451 // Filter noisy false positives.
452 unless(isMacro()), unless(isInTemplateInstantiation()))
453 .bind(OverloadId);
454
455 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
456 NegateNegateRelationalExpr, OverloadedOperatorExpr);
457 }
458
459 // Checks whether a function param is non constant reference type, and may
460 // be modified in the function.
461 static bool isNonConstReferenceType(QualType ParamType) {
462 return ParamType->isReferenceType() &&
463 !ParamType.getNonReferenceType().isConstQualified();
464 }
465
466 // Checks whether the arguments of an overloaded operator can be modified in the
467 // function.
468 // For operators that take an instance and a constant as arguments, only the
469 // first argument (the instance) needs to be checked, since the constant itself
470 // is a temporary expression. Whether the second parameter is checked is
471 // controlled by the parameter `ParamsToCheckCount`.
472 static bool
473 canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl,
474 bool checkSecondParam) {
475 unsigned ParamCount = OperatorDecl->getNumParams();
476
477 // Overloaded operators declared inside a class have only one param.
478 // These functions must be declared const in order to not be able to modify
479 // the instance of the class they are called through.
480 if (ParamCount == 1 &&
481 !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
482 return true;
483
484 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
485 return true;
486
487 return checkSecondParam && ParamCount == 2 &&
488 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
489 }
490
491 // Retrieves sub-expressions matched by 'matchRelationalIntegerConstantExpr'
492 // with name 'Id'.
493 static bool retrieveRelationalIntegerConstantExpr(
494 const MatchFinder::MatchResult &Result, StringRef Id,
495 const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol,
496 APSInt &Value, const Expr *&ConstExpr) {
497 std::string CastId = (Id + "-cast").str();
498 std::string SwapId = (Id + "-swap").str();
499 std::string NegateId = (Id + "-negate").str();
500 std::string OverloadId = (Id + "-overload").str();
501
502 if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
503 // Operand received with explicit comparator.
504 Opcode = Bin->getOpcode();
505 OperandExpr = Bin;
506
507 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
508 return false;
509 } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
510 // Operand received with implicit comparator (cast).
511 Opcode = BO_NE;
512 OperandExpr = Cast;
513 Value = APSInt(32, false);
514 } else if (const auto *OverloadedOperatorExpr =
515 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
516 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
517 if (!OverloadedFunctionDecl)
518 return false;
519
520 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
521 return false;
522
523 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
524 return false;
525
526 if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
527 Value, *Result.Context))
528 return false;
529
530 Symbol = OverloadedOperatorExpr->getArg(0);
531 OperandExpr = OverloadedOperatorExpr;
532 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
533
534 return BinaryOperator::isComparisonOp(Opcode);
535 } else {
536 return false;
537 }
538
539 if (!retrieveSymbolicExpr(Result, Id, Symbol))
540 return false;
541
542 if (Result.Nodes.getNodeAs<Expr>(SwapId))
543 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
544 if (Result.Nodes.getNodeAs<Expr>(NegateId))
545 Opcode = BinaryOperator::negateComparisonOp(Opcode);
546 return true;
547 }
548
549 // Checks for expressions like (X == 4) && (Y != 9)
550 static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
551 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
552 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
553
554 if (!LhsBinOp || !RhsBinOp)
555 return false;
556
557 if ((LhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
558 LhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)) &&
559 (RhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
560 RhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)))
561 return true;
562 return false;
563 }
564
565 // Retrieves integer constant subexpressions from binary operator expressions
566 // that have two equivalent sides.
567 // E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
568 static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
569 BinaryOperatorKind &MainOpcode,
570 BinaryOperatorKind &SideOpcode,
571 const Expr *&LhsConst,
572 const Expr *&RhsConst,
573 const ASTContext *AstCtx) {
574 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
575 "Both sides of binary operator must be constant expressions!");
576
577 MainOpcode = BinOp->getOpcode();
578
579 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
580 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
581
582 LhsConst = BinOpLhs->getLHS()->isIntegerConstantExpr(*AstCtx)
583 ? BinOpLhs->getLHS()
584 : BinOpLhs->getRHS();
585 RhsConst = BinOpRhs->getLHS()->isIntegerConstantExpr(*AstCtx)
586 ? BinOpRhs->getLHS()
587 : BinOpRhs->getRHS();
588
589 if (!LhsConst || !RhsConst)
590 return false;
591
592 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
593 "Sides of the binary operator must be equivalent expressions!");
594
595 SideOpcode = BinOpLhs->getOpcode();
596
597 return true;
598 }
599
600 static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
601 const Expr *RhsExpr,
602 const ASTContext *AstCtx) {
603 if (!LhsExpr || !RhsExpr)
604 return false;
605
606 SourceLocation LhsLoc = LhsExpr->getExprLoc();
607 SourceLocation RhsLoc = RhsExpr->getExprLoc();
608
609 if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
610 return false;
611
612 const SourceManager &SM = AstCtx->getSourceManager();
613 const LangOptions &LO = AstCtx->getLangOpts();
614
615 return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
616 Lexer::getImmediateMacroName(RhsLoc, SM, LO));
617 }
618
619 static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
620 const Expr *&RhsExpr) {
621 if (!LhsExpr || !RhsExpr)
622 return false;
623
624 SourceLocation LhsLoc = LhsExpr->getExprLoc();
625 SourceLocation RhsLoc = RhsExpr->getExprLoc();
626
627 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
628 }
629
630 void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
631 const auto AnyLiteralExpr = ignoringParenImpCasts(
632 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
633
634 const auto BannedIntegerLiteral =
635 integerLiteral(expandedByMacro(KnownBannedMacroNames));
636
637 // Binary with equivalent operands, like (X != 2 && X != 2).
638 Finder->addMatcher(
639 binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
640 hasOperatorName("%"), hasOperatorName("|"),
641 hasOperatorName("&"), hasOperatorName("^"),
642 matchers::isComparisonOperator(),
643 hasOperatorName("&&"), hasOperatorName("||"),
644 hasOperatorName("=")),
645 operandsAreEquivalent(),
646 // Filter noisy false positives.
647 unless(isInTemplateInstantiation()),
648 unless(binaryOperatorIsInMacro()),
649 unless(hasType(realFloatingPointType())),
650 unless(hasEitherOperand(hasType(realFloatingPointType()))),
651 unless(hasLHS(AnyLiteralExpr)),
652 unless(hasDescendant(BannedIntegerLiteral)))
653 .bind("binary"),
654 this);
655
656 // Conditional (trenary) operator with equivalent operands, like (Y ? X : X).
657 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
658 // Filter noisy false positives.
659 unless(conditionalOperatorIsInMacro()),
660 unless(isInTemplateInstantiation()))
661 .bind("cond"),
662 this);
663
664 // Overloaded operators with equivalent operands.
665 Finder->addMatcher(
666 cxxOperatorCallExpr(
667 anyOf(
668 hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"),
669 hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"),
670 hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"),
671 hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="),
672 hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="),
673 hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="),
674 hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"),
675 hasOverloadedOperatorName("=")),
676 parametersAreEquivalent(),
677 // Filter noisy false positives.
678 unless(isMacro()), unless(isInTemplateInstantiation()))
679 .bind("call"),
680 this);
681
682 // Match expressions like: !(1 | 2 | 3)
683 Finder->addMatcher(
684 implicitCastExpr(
685 hasImplicitDestinationType(isInteger()),
686 has(unaryOperator(
687 hasOperatorName("!"),
688 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
689 anyOf(hasOperatorName("|"), hasOperatorName("&")),
690 hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName("|"),
691 hasOperatorName("&"))),
692 integerLiteral())),
693 hasRHS(integerLiteral())))))
694 .bind("logical-bitwise-confusion"))),
695 this);
696
697 // Match expressions like: (X << 8) & 0xFF
698 Finder->addMatcher(
699 binaryOperator(hasOperatorName("&"),
700 hasEitherOperand(ignoringParenImpCasts(binaryOperator(
701 hasOperatorName("<<"),
702 hasRHS(ignoringParenImpCasts(
703 integerLiteral().bind("shift-const")))))),
704 hasEitherOperand(ignoringParenImpCasts(
705 integerLiteral().bind("and-const"))))
706 .bind("left-right-shift-confusion"),
707 this);
708
709 // Match common expressions and apply more checks to find redundant
710 // sub-expressions.
711 // a) Expr <op> K1 == K2
712 // b) Expr <op> K1 == Expr
713 // c) Expr <op> K1 == Expr <op> K2
714 // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
715 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
716 const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
717 const auto CstRight = matchIntegerConstantExpr("rhs");
718 const auto SymRight = matchSymbolicExpr("rhs");
719
720 // Match expressions like: x <op> 0xFF == 0xF00.
721 Finder->addMatcher(binaryOperator(isComparisonOperator(),
722 hasEitherOperand(BinOpCstLeft),
723 hasEitherOperand(CstRight))
724 .bind("binop-const-compare-to-const"),
725 this);
726
727 // Match expressions like: x <op> 0xFF == x.
728 Finder->addMatcher(
729 binaryOperator(isComparisonOperator(),
730 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
731 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
732 .bind("binop-const-compare-to-sym"),
733 this);
734
735 // Match expressions like: x <op> 10 == x <op> 12.
736 Finder->addMatcher(binaryOperator(isComparisonOperator(),
737 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
738 // Already reported as redundant.
739 unless(operandsAreEquivalent()))
740 .bind("binop-const-compare-to-binop-const"),
741 this);
742
743 // Match relational expressions combined with logical operators and find
744 // redundant sub-expressions.
745 // see: 'checkRelationalExpr'
746
747 // Match expressions like: x < 2 && x > 2.
748 const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
749 const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
750 Finder->addMatcher(
751 binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")),
752 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
753 // Already reported as redundant.
754 unless(operandsAreEquivalent()))
755 .bind("comparisons-of-symbol-and-const"),
756 this);
757 }
758
759 void RedundantExpressionCheck::checkArithmeticExpr(
760 const MatchFinder::MatchResult &Result) {
761 APSInt LhsValue, RhsValue;
762 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
763 BinaryOperatorKind LhsOpcode, RhsOpcode;
764
765 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
766 "binop-const-compare-to-sym")) {
767 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
768 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
769 LhsValue) ||
770 !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
771 !areEquivalentExpr(LhsSymbol, RhsSymbol))
772 return;
773
774 // Check expressions: x + k == x or x - k == x.
775 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
776 if ((LhsValue != 0 && Opcode == BO_EQ) ||
777 (LhsValue == 0 && Opcode == BO_NE))
778 diag(ComparisonOperator->getOperatorLoc(),
779 "logical expression is always false");
780 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
781 (LhsValue != 0 && Opcode == BO_NE))
782 diag(ComparisonOperator->getOperatorLoc(),
783 "logical expression is always true");
784 }
785 } else if (const auto *ComparisonOperator =
786 Result.Nodes.getNodeAs<BinaryOperator>(
787 "binop-const-compare-to-binop-const")) {
788 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
789
790 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
791 LhsValue) ||
792 !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
793 RhsValue) ||
794 !areEquivalentExpr(LhsSymbol, RhsSymbol))
795 return;
796
797 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
798 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
799
800 // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
801 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
802 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
803 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
804 diag(ComparisonOperator->getOperatorLoc(),
805 "logical expression is always true");
806 } else if ((Opcode == BO_EQ &&
807 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
808 (Opcode == BO_NE &&
809 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
810 diag(ComparisonOperator->getOperatorLoc(),
811 "logical expression is always false");
812 }
813 }
814 }
815 }
816
817 static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value) {
818 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
819 }
820
821 static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode,
822 APSInt Value) {
823 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
824 }
825
826 static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value) {
827 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
828 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
829 }
830
831
832 void RedundantExpressionCheck::checkBitwiseExpr(
833 const MatchFinder::MatchResult &Result) {
834 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
835 "binop-const-compare-to-const")) {
836 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
837
838 APSInt LhsValue, RhsValue;
839 const Expr *LhsSymbol = nullptr;
840 BinaryOperatorKind LhsOpcode;
841 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
842 LhsValue) ||
843 !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
844 return;
845
846 uint64_t LhsConstant = LhsValue.getZExtValue();
847 uint64_t RhsConstant = RhsValue.getZExtValue();
848 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
849
850 // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
851 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
852 if (Opcode == BO_EQ)
853 diag(Loc, "logical expression is always false");
854 else if (Opcode == BO_NE)
855 diag(Loc, "logical expression is always true");
856 }
857
858 // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
859 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
860 if (Opcode == BO_EQ)
861 diag(Loc, "logical expression is always false");
862 else if (Opcode == BO_NE)
863 diag(Loc, "logical expression is always true");
864 }
865 } else if (const auto *IneffectiveOperator =
866 Result.Nodes.getNodeAs<BinaryOperator>(
867 "ineffective-bitwise")) {
868 APSInt Value;
869 const Expr *Sym = nullptr, *ConstExpr = nullptr;
870
871 if (!retrieveSymbolicExpr(Result, "ineffective-bitwise", Sym) ||
872 !retrieveIntegerConstantExpr(Result, "ineffective-bitwise", Value,
873 ConstExpr))
874 return;
875
876 if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
877 return;
878
879 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
880
881 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
882 if (exprEvaluatesToZero(Opcode, Value)) {
883 diag(Loc, "expression always evaluates to 0");
884 } else if (exprEvaluatesToBitwiseNegatedZero(Opcode, Value)) {
885 SourceRange ConstExprRange(ConstExpr->getLocStart(),
886 ConstExpr->getLocEnd());
887 StringRef ConstExprText = Lexer::getSourceText(
888 CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
889 Result.Context->getLangOpts());
890
891 diag(Loc, "expression always evaluates to '%0'") << ConstExprText;
892
893 } else if (exprEvaluatesToSymbolic(Opcode, Value)) {
894 SourceRange SymExprRange(Sym->getLocStart(), Sym->getLocEnd());
895
896 StringRef ExprText = Lexer::getSourceText(
897 CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
898 Result.Context->getLangOpts());
899
900 diag(Loc, "expression always evaluates to '%0'") << ExprText;
901 }
902 }
903 }
904
905 void RedundantExpressionCheck::checkRelationalExpr(
906 const MatchFinder::MatchResult &Result) {
907 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
908 "comparisons-of-symbol-and-const")) {
909 // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
910 // E.g.: (X < 2) && (X > 4)
911 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
912
913 const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
914 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
915 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
916 BinaryOperatorKind LhsOpcode, RhsOpcode;
917 APSInt LhsValue, RhsValue;
918
919 if (!retrieveRelationalIntegerConstantExpr(
920 Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
921 !retrieveRelationalIntegerConstantExpr(
922 Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
923 !areEquivalentExpr(LhsSymbol, RhsSymbol))
924 return;
925
926 // Bring expr to a canonical form: smallest constant must be on the left.
927 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
928 std::swap(LhsExpr, RhsExpr);
929 std::swap(LhsValue, RhsValue);
930 std::swap(LhsSymbol, RhsSymbol);
931 std::swap(LhsOpcode, RhsOpcode);
932 }
933
934 // Constants come from two different macros, or one of them is a macro.
935 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
936 areExprsMacroAndNonMacro(LhsConst, RhsConst))
937 return;
938
939 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
940 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
941 diag(ComparisonOperator->getOperatorLoc(),
942 "equivalent expression on both sides of logical operator");
943 return;
944 }
945
946 if (Opcode == BO_LAnd) {
947 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
948 diag(ComparisonOperator->getOperatorLoc(),
949 "logical expression is always false");
950 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
951 diag(LhsExpr->getExprLoc(), "expression is redundant");
952 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
953 diag(RhsExpr->getExprLoc(), "expression is redundant");
954 }
955 }
956
957 if (Opcode == BO_LOr) {
958 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
959 diag(ComparisonOperator->getOperatorLoc(),
960 "logical expression is always true");
961 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
962 diag(RhsExpr->getExprLoc(), "expression is redundant");
963 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
964 diag(LhsExpr->getExprLoc(), "expression is redundant");
965 }
966 }
967 }
968 }
969
970 void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
971 if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
972 // If the expression's constants are macros, check whether they are
973 // intentional.
974 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
975 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
976 BinaryOperatorKind MainOpcode, SideOpcode;
977
978 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
979 LhsConst, RhsConst, Result.Context))
980 return;
981
982 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
983 areExprsMacroAndNonMacro(LhsConst, RhsConst))
984 return;
985 }
986
987 diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
988 }
989
990 if (const auto *CondOp =
991 Result.Nodes.getNodeAs<ConditionalOperator>("cond")) {
992 const Expr *TrueExpr = CondOp->getTrueExpr();
993 const Expr *FalseExpr = CondOp->getFalseExpr();
994
995 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
996 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
997 return;
998 diag(CondOp->getColonLoc(),
999 "'true' and 'false' expressions are equivalent");
1000 }
1001
1002 if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
1003 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
1004 if (!OverloadedFunctionDecl)
1005 return;
1006
1007 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, true))
1008 return;
1009
1010 diag(Call->getOperatorLoc(),
1011 "both sides of overloaded operator are equivalent");
1012 }
1013
1014 if (const auto *NegateOperator =
1015 Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
1016 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1017
1018 auto Diag =
1019 diag(OperatorLoc,
1020 "ineffective logical negation operator used; did you mean '~'?");
1021 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1022
1023 if (!LogicalNotLocation.isMacroID())
1024 Diag << FixItHint::CreateReplacement(
1025 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation), "~");
1026 }
1027
1028 if (const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1029 "left-right-shift-confusion")) {
1030 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>("shift-const");
1031 assert(ShiftingConst && "Expr* 'ShiftingConst' is nullptr!");
1032 APSInt ShiftingValue;
1033
1034 if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
1035 return;
1036
1037 const auto *AndConst = Result.Nodes.getNodeAs<Expr>("and-const");
1038 assert(AndConst && "Expr* 'AndCont' is nullptr!");
1039 APSInt AndValue;
1040 if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
1041 return;
1042
1043 // If ShiftingConst is shifted left with more bits than the position of the
1044 // leftmost 1 in the bit representation of AndValue, AndConstant is
1045 // ineffective.
1046 if (floor(log2(AndValue.getExtValue())) >= ShiftingValue)
1047 return;
1048
1049 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
1050 "ineffective bitwise and operation.");
1051 }
1052
1053 // Check for the following bound expressions:
1054 // - "binop-const-compare-to-sym",
1055 // - "binop-const-compare-to-binop-const",
1056 // Produced message:
1057 // -> "logical expression is always false/true"
1058 checkArithmeticExpr(Result);
1059
1060 // Check for the following bound expression:
1061 // - "binop-const-compare-to-const",
1062 // - "ineffective-bitwise"
1063 // Produced message:
1064 // -> "logical expression is always false/true"
1065 // -> "expression always evaluates to ..."
1066 checkBitwiseExpr(Result);
1067
1068 // Check for te following bound expression:
1069 // - "comparisons-of-symbol-and-const",
1070 // Produced messages:
1071 // -> "equivalent expression on both sides of logical operator",
1072 // -> "logical expression is always false/true"
1073 // -> "expression is redundant"
1074 checkRelationalExpr(Result);
1075 }
1076
1077 } // namespace misc
1078 } // namespace tidy
1079 } // namespace clang
Loc
SourceLocation Loc
&#39;#&#39; location in the include directive
Definition: IncludeOrderCheck.cpp:36
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
clang::tidy::misc::exprEvaluatesToZero
static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value)
Definition: RedundantExpressionCheck.cpp:817
clang::tidy::misc::matchRelationalIntegerConstantExpr
static ast_matchers::internal::Matcher< Expr > matchRelationalIntegerConstantExpr(StringRef Id)
Definition: RedundantExpressionCheck.cpp:413
clang::tidy::misc::rangesFullyCoverDomain
static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
Definition: RedundantExpressionCheck.cpp:203
clang::tidy::misc::areExprsFromDifferentMacros
static bool areExprsFromDifferentMacros(const Expr *LhsExpr, const Expr *RhsExpr, const ASTContext *AstCtx)
Definition: RedundantExpressionCheck.cpp:600
clang::tidy::misc::retrieveIntegerConstantExpr
static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, APSInt &Value)
Definition: RedundantExpressionCheck.cpp:354
RedundantExpressionCheck.h
clang::tidy::misc::retrieveConstExprFromBothSides
static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp, BinaryOperatorKind &MainOpcode, BinaryOperatorKind &SideOpcode, const Expr *&LhsConst, const Expr *&RhsConst, const ASTContext *AstCtx)
Definition: RedundantExpressionCheck.cpp:568
clang::tidy::misc::rangeSubsumesRange
static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
Definition: RedundantExpressionCheck.cpp:250
clang::tidy::misc::areEquivalentNameSpecifier
static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, const NestedNameSpecifier *Right)
Definition: RedundantExpressionCheck.cpp:50
clang::tidy::matchers
Definition: Matchers.h:18
clang::tidy::misc::isNonConstReferenceType
static bool isNonConstReferenceType(QualType ParamType)
Definition: RedundantExpressionCheck.cpp:461
clang::tidy::misc::exprEvaluatesToSymbolic
static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value)
Definition: RedundantExpressionCheck.cpp:826
clang::tidy::misc::transformSubToCanonicalAddExpr
static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode, APSInt &Value)
Definition: RedundantExpressionCheck.cpp:285
clang::tidy::misc::exprEvaluatesToBitwiseNegatedZero
static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode, APSInt Value)
Definition: RedundantExpressionCheck.cpp:821
clang::tidy::misc::areSidesBinaryConstExpressions
static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx)
Definition: RedundantExpressionCheck.cpp:550
clang::tidy::misc::incrementWithoutOverflow
static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result)
Definition: RedundantExpressionCheck.cpp:44
clang::tidy::misc::retrieveRelationalIntegerConstantExpr
static bool retrieveRelationalIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value, const Expr *&ConstExpr)
Definition: RedundantExpressionCheck.cpp:493
clang::tidy::misc::areEquivalentRanges
static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
Definition: RedundantExpressionCheck.cpp:139
clang::tidy::misc::matchSymbolicExpr
static ast_matchers::internal::Matcher< Expr > matchSymbolicExpr(StringRef Id)
Definition: RedundantExpressionCheck.cpp:362
clang::tidy::misc::canOverloadedOperatorArgsBeModified
static bool canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl, bool checkSecondParam)
Definition: RedundantExpressionCheck.cpp:473
clang::tidy::misc::retrieveSymbolicExpr
static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result, StringRef Id, const Expr *&SymExpr)
Definition: RedundantExpressionCheck.cpp:370
clang::tidy::misc::areExclusiveRanges
static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS, const APSInt &ValueLHS, BinaryOperatorKind OpcodeRHS, const APSInt &ValueRHS)
Definition: RedundantExpressionCheck.cpp:159
clang
Definition: AndroidTidyModule.cpp:28
clang::tidy::misc::areEquivalentExpr
static bool areEquivalentExpr(const Expr *Left, const Expr *Right)
Definition: RedundantExpressionCheck.cpp:58
clang::tidy::misc::retrieveBinOpIntegerConstantExpr
static bool retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result, StringRef Id, BinaryOperatorKind &Opcode, const Expr *&Symbol, APSInt &Value)
Definition: RedundantExpressionCheck.cpp:400
clang::tidy::misc::KnownBannedMacroNames
static const llvm::StringSet KnownBannedMacroNames
Definition: RedundantExpressionCheck.cpp:41
clang::tidy::misc::areExprsMacroAndNonMacro
static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr, const Expr *&RhsExpr)
Definition: RedundantExpressionCheck.cpp:619
clang::tidy::misc::matchBinOpIntegerConstantExpr
static ast_matchers::internal::Matcher< Expr > matchBinOpIntegerConstantExpr(StringRef Id)
Definition: RedundantExpressionCheck.cpp:383
clang::tidy::misc::matchIntegerConstantExpr
static ast_matchers::internal::Matcher< Expr > matchIntegerConstantExpr(StringRef Id)
Definition: RedundantExpressionCheck.cpp:337
clang::ast_matchers::AST_MATCHER
AST_MATCHER(VarDecl, isAsm)
Definition: NoAssemblerCheck.cpp:18
clang::tidy::misc::AST_MATCHER_P
AST_MATCHER_P(Expr, expandedByMacro, llvm::StringSet<>, Names)
Definition: RedundantExpressionCheck.cpp:322