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->getLocStart(), 888 ConstExpr->getLocEnd()); 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->getLocStart(), Sym->getLocEnd()); 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 1082