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