IdempotentOperationChecker.cpp revision cf995d357759221f0a3b9fcd9315b004a4aa38ad
1//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- C++ -*-==// 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// This file defines a set of path-sensitive checks for idempotent and/or 11// tautological operations. Each potential operation is checked along all paths 12// to see if every path results in a pointless operation. 13// +-------------------------------------------+ 14// |Table of idempotent/tautological operations| 15// +-------------------------------------------+ 16//+--------------------------------------------------------------------------+ 17//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x | 18//+--------------------------------------------------------------------------+ 19// +, += | | | | x | x | | 20// -, -= | | | | x | -x | | 21// *, *= | | x | x | 0 | 0 | | 22// /, /= | 1 | x | | N/A | 0 | | 23// &, &= | x | | | 0 | 0 | x | x 24// |, |= | x | | | x | x | ~0 | ~0 25// ^, ^= | 0 | | | x | x | | 26// <<, <<= | | | | x | 0 | | 27// >>, >>= | | | | x | 0 | | 28// || | 1 | 1 | 1 | x | x | 1 | 1 29// && | 1 | x | x | 0 | 0 | x | x 30// = | x | | | | | | 31// == | 1 | | | | | | 32// >= | 1 | | | | | | 33// <= | 1 | | | | | | 34// > | 0 | | | | | | 35// < | 0 | | | | | | 36// != | 0 | | | | | | 37//===----------------------------------------------------------------------===// 38// 39// Things TODO: 40// - Improved error messages 41// - Handle mixed assumptions (which assumptions can belong together?) 42// - Finer grained false positive control (levels) 43// - Handling ~0 values 44 45#include "ClangSACheckers.h" 46#include "clang/Analysis/CFGStmtMap.h" 47#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" 48#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" 49#include "clang/StaticAnalyzer/Core/Checker.h" 50#include "clang/StaticAnalyzer/Core/CheckerManager.h" 51#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 52#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 53#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 54#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" 55#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" 56#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 57#include "clang/AST/Stmt.h" 58#include "llvm/ADT/DenseMap.h" 59#include "llvm/ADT/SmallSet.h" 60#include "llvm/ADT/BitVector.h" 61#include "llvm/Support/ErrorHandling.h" 62#include <deque> 63 64using namespace clang; 65using namespace ento; 66 67namespace { 68class IdempotentOperationChecker 69 : public Checker<check::PreStmt<BinaryOperator>, 70 check::PostStmt<BinaryOperator>, 71 check::EndAnalysis> { 72public: 73 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; 74 void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; 75 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const; 76 77private: 78 // Our assumption about a particular operation. 79 enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0, 80 RHSis0 }; 81 82 static void UpdateAssumption(Assumption &A, const Assumption &New); 83 84 // False positive reduction methods 85 static bool isSelfAssign(const Expr *LHS, const Expr *RHS); 86 static bool isUnused(const Expr *E, AnalysisContext *AC); 87 static bool isTruncationExtensionAssignment(const Expr *LHS, 88 const Expr *RHS); 89 static bool pathWasCompletelyAnalyzed(AnalysisContext *AC, 90 const CFGBlock *CB, 91 const CoreEngine &CE); 92 static bool CanVary(const Expr *Ex, 93 AnalysisContext *AC); 94 static bool isConstantOrPseudoConstant(const DeclRefExpr *DR, 95 AnalysisContext *AC); 96 static bool containsNonLocalVarDecl(const Stmt *S); 97 98 // Hash table and related data structures 99 struct BinaryOperatorData { 100 BinaryOperatorData() : assumption(Possible), analysisContext(0) {} 101 102 Assumption assumption; 103 AnalysisContext *analysisContext; 104 ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a 105 // BinaryOperator 106 }; 107 typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData> 108 AssumptionMap; 109 mutable AssumptionMap hash; 110}; 111} 112 113void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B, 114 CheckerContext &C) const { 115 // Find or create an entry in the hash for this BinaryOperator instance. 116 // If we haven't done a lookup before, it will get default initialized to 117 // 'Possible'. At this stage we do not store the ExplodedNode, as it has not 118 // been created yet. 119 BinaryOperatorData &Data = hash[B]; 120 Assumption &A = Data.assumption; 121 AnalysisContext *AC = C.getCurrentAnalysisContext(); 122 Data.analysisContext = AC; 123 124 // If we already have visited this node on a path that does not contain an 125 // idempotent operation, return immediately. 126 if (A == Impossible) 127 return; 128 129 // Retrieve both sides of the operator and determine if they can vary (which 130 // may mean this is a false positive. 131 const Expr *LHS = B->getLHS(); 132 const Expr *RHS = B->getRHS(); 133 134 // At this stage we can calculate whether each side contains a false positive 135 // that applies to all operators. We only need to calculate this the first 136 // time. 137 bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false; 138 if (A == Possible) { 139 // An expression contains a false positive if it can't vary, or if it 140 // contains a known false positive VarDecl. 141 LHSContainsFalsePositive = !CanVary(LHS, AC) 142 || containsNonLocalVarDecl(LHS); 143 RHSContainsFalsePositive = !CanVary(RHS, AC) 144 || containsNonLocalVarDecl(RHS); 145 } 146 147 const GRState *state = C.getState(); 148 149 SVal LHSVal = state->getSVal(LHS); 150 SVal RHSVal = state->getSVal(RHS); 151 152 // If either value is unknown, we can't be 100% sure of all paths. 153 if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) { 154 A = Impossible; 155 return; 156 } 157 BinaryOperator::Opcode Op = B->getOpcode(); 158 159 // Dereference the LHS SVal if this is an assign operation 160 switch (Op) { 161 default: 162 break; 163 164 // Fall through intentional 165 case BO_AddAssign: 166 case BO_SubAssign: 167 case BO_MulAssign: 168 case BO_DivAssign: 169 case BO_AndAssign: 170 case BO_OrAssign: 171 case BO_XorAssign: 172 case BO_ShlAssign: 173 case BO_ShrAssign: 174 case BO_Assign: 175 // Assign statements have one extra level of indirection 176 if (!isa<Loc>(LHSVal)) { 177 A = Impossible; 178 return; 179 } 180 LHSVal = state->getSVal(cast<Loc>(LHSVal), LHS->getType()); 181 } 182 183 184 // We now check for various cases which result in an idempotent operation. 185 186 // x op x 187 switch (Op) { 188 default: 189 break; // We don't care about any other operators. 190 191 // Fall through intentional 192 case BO_Assign: 193 // x Assign x can be used to silence unused variable warnings intentionally. 194 // If this is a self assignment and the variable is referenced elsewhere, 195 // and the assignment is not a truncation or extension, then it is a false 196 // positive. 197 if (isSelfAssign(LHS, RHS)) { 198 if (!isUnused(LHS, AC) && !isTruncationExtensionAssignment(LHS, RHS)) { 199 UpdateAssumption(A, Equal); 200 return; 201 } 202 else { 203 A = Impossible; 204 return; 205 } 206 } 207 208 case BO_SubAssign: 209 case BO_DivAssign: 210 case BO_AndAssign: 211 case BO_OrAssign: 212 case BO_XorAssign: 213 case BO_Sub: 214 case BO_Div: 215 case BO_And: 216 case BO_Or: 217 case BO_Xor: 218 case BO_LOr: 219 case BO_LAnd: 220 case BO_EQ: 221 case BO_NE: 222 if (LHSVal != RHSVal || LHSContainsFalsePositive 223 || RHSContainsFalsePositive) 224 break; 225 UpdateAssumption(A, Equal); 226 return; 227 } 228 229 // x op 1 230 switch (Op) { 231 default: 232 break; // We don't care about any other operators. 233 234 // Fall through intentional 235 case BO_MulAssign: 236 case BO_DivAssign: 237 case BO_Mul: 238 case BO_Div: 239 case BO_LOr: 240 case BO_LAnd: 241 if (!RHSVal.isConstant(1) || RHSContainsFalsePositive) 242 break; 243 UpdateAssumption(A, RHSis1); 244 return; 245 } 246 247 // 1 op x 248 switch (Op) { 249 default: 250 break; // We don't care about any other operators. 251 252 // Fall through intentional 253 case BO_MulAssign: 254 case BO_Mul: 255 case BO_LOr: 256 case BO_LAnd: 257 if (!LHSVal.isConstant(1) || LHSContainsFalsePositive) 258 break; 259 UpdateAssumption(A, LHSis1); 260 return; 261 } 262 263 // x op 0 264 switch (Op) { 265 default: 266 break; // We don't care about any other operators. 267 268 // Fall through intentional 269 case BO_AddAssign: 270 case BO_SubAssign: 271 case BO_MulAssign: 272 case BO_AndAssign: 273 case BO_OrAssign: 274 case BO_XorAssign: 275 case BO_Add: 276 case BO_Sub: 277 case BO_Mul: 278 case BO_And: 279 case BO_Or: 280 case BO_Xor: 281 case BO_Shl: 282 case BO_Shr: 283 case BO_LOr: 284 case BO_LAnd: 285 if (!RHSVal.isConstant(0) || RHSContainsFalsePositive) 286 break; 287 UpdateAssumption(A, RHSis0); 288 return; 289 } 290 291 // 0 op x 292 switch (Op) { 293 default: 294 break; // We don't care about any other operators. 295 296 // Fall through intentional 297 //case BO_AddAssign: // Common false positive 298 case BO_SubAssign: // Check only if unsigned 299 case BO_MulAssign: 300 case BO_DivAssign: 301 case BO_AndAssign: 302 //case BO_OrAssign: // Common false positive 303 //case BO_XorAssign: // Common false positive 304 case BO_ShlAssign: 305 case BO_ShrAssign: 306 case BO_Add: 307 case BO_Sub: 308 case BO_Mul: 309 case BO_Div: 310 case BO_And: 311 case BO_Or: 312 case BO_Xor: 313 case BO_Shl: 314 case BO_Shr: 315 case BO_LOr: 316 case BO_LAnd: 317 if (!LHSVal.isConstant(0) || LHSContainsFalsePositive) 318 break; 319 UpdateAssumption(A, LHSis0); 320 return; 321 } 322 323 // If we get to this point, there has been a valid use of this operation. 324 A = Impossible; 325} 326 327// At the post visit stage, the predecessor ExplodedNode will be the 328// BinaryOperator that was just created. We use this hook to collect the 329// ExplodedNode. 330void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B, 331 CheckerContext &C) const { 332 // Add the ExplodedNode we just visited 333 BinaryOperatorData &Data = hash[B]; 334 335 const Stmt *predStmt 336 = cast<StmtPoint>(C.getPredecessor()->getLocation()).getStmt(); 337 338 // Ignore implicit calls to setters. 339 if (!isa<BinaryOperator>(predStmt)) 340 return; 341 342 Data.explodedNodes.Add(C.getPredecessor()); 343} 344 345void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, 346 BugReporter &BR, 347 ExprEngine &Eng) const { 348 BugType *BT = new BugType("Idempotent operation", "Dead code"); 349 // Iterate over the hash to see if we have any paths with definite 350 // idempotent operations. 351 for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) { 352 // Unpack the hash contents 353 const BinaryOperatorData &Data = i->second; 354 const Assumption &A = Data.assumption; 355 AnalysisContext *AC = Data.analysisContext; 356 const ExplodedNodeSet &ES = Data.explodedNodes; 357 358 const BinaryOperator *B = i->first; 359 360 if (A == Impossible) 361 continue; 362 363 // If the analyzer did not finish, check to see if we can still emit this 364 // warning 365 if (Eng.hasWorkRemaining()) { 366 // If we can trace back 367 if (!pathWasCompletelyAnalyzed(AC, 368 AC->getCFGStmtMap()->getBlock(B), 369 Eng.getCoreEngine())) 370 continue; 371 } 372 373 // Select the error message and SourceRanges to report. 374 llvm::SmallString<128> buf; 375 llvm::raw_svector_ostream os(buf); 376 bool LHSRelevant = false, RHSRelevant = false; 377 switch (A) { 378 case Equal: 379 LHSRelevant = true; 380 RHSRelevant = true; 381 if (B->getOpcode() == BO_Assign) 382 os << "Assigned value is always the same as the existing value"; 383 else 384 os << "Both operands to '" << B->getOpcodeStr() 385 << "' always have the same value"; 386 break; 387 case LHSis1: 388 LHSRelevant = true; 389 os << "The left operand to '" << B->getOpcodeStr() << "' is always 1"; 390 break; 391 case RHSis1: 392 RHSRelevant = true; 393 os << "The right operand to '" << B->getOpcodeStr() << "' is always 1"; 394 break; 395 case LHSis0: 396 LHSRelevant = true; 397 os << "The left operand to '" << B->getOpcodeStr() << "' is always 0"; 398 break; 399 case RHSis0: 400 RHSRelevant = true; 401 os << "The right operand to '" << B->getOpcodeStr() << "' is always 0"; 402 break; 403 case Possible: 404 llvm_unreachable("Operation was never marked with an assumption"); 405 case Impossible: 406 llvm_unreachable(0); 407 } 408 409 // Add a report for each ExplodedNode 410 for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) { 411 EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I); 412 413 // Add source ranges and visitor hooks 414 if (LHSRelevant) { 415 const Expr *LHS = i->first->getLHS(); 416 report->addRange(LHS->getSourceRange()); 417 report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS); 418 } 419 if (RHSRelevant) { 420 const Expr *RHS = i->first->getRHS(); 421 report->addRange(i->first->getRHS()->getSourceRange()); 422 report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS); 423 } 424 425 BR.EmitReport(report); 426 } 427 } 428 429 hash.clear(); 430} 431 432// Updates the current assumption given the new assumption 433inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A, 434 const Assumption &New) { 435// If the assumption is the same, there is nothing to do 436 if (A == New) 437 return; 438 439 switch (A) { 440 // If we don't currently have an assumption, set it 441 case Possible: 442 A = New; 443 return; 444 445 // If we have determined that a valid state happened, ignore the new 446 // assumption. 447 case Impossible: 448 return; 449 450 // Any other case means that we had a different assumption last time. We don't 451 // currently support mixing assumptions for diagnostic reasons, so we set 452 // our assumption to be impossible. 453 default: 454 A = Impossible; 455 return; 456 } 457} 458 459// Check for a statement where a variable is self assigned to possibly avoid an 460// unused variable warning. 461bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) { 462 LHS = LHS->IgnoreParenCasts(); 463 RHS = RHS->IgnoreParenCasts(); 464 465 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS); 466 if (!LHS_DR) 467 return false; 468 469 const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl()); 470 if (!VD) 471 return false; 472 473 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS); 474 if (!RHS_DR) 475 return false; 476 477 if (VD != RHS_DR->getDecl()) 478 return false; 479 480 return true; 481} 482 483// Returns true if the Expr points to a VarDecl that is not read anywhere 484// outside of self-assignments. 485bool IdempotentOperationChecker::isUnused(const Expr *E, 486 AnalysisContext *AC) { 487 if (!E) 488 return false; 489 490 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()); 491 if (!DR) 492 return false; 493 494 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 495 if (!VD) 496 return false; 497 498 if (AC->getPseudoConstantAnalysis()->wasReferenced(VD)) 499 return false; 500 501 return true; 502} 503 504// Check for self casts truncating/extending a variable 505bool IdempotentOperationChecker::isTruncationExtensionAssignment( 506 const Expr *LHS, 507 const Expr *RHS) { 508 509 const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts()); 510 if (!LHS_DR) 511 return false; 512 513 const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl()); 514 if (!VD) 515 return false; 516 517 const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts()); 518 if (!RHS_DR) 519 return false; 520 521 if (VD != RHS_DR->getDecl()) 522 return false; 523 524 return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL; 525} 526 527// Returns false if a path to this block was not completely analyzed, or true 528// otherwise. 529bool 530IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC, 531 const CFGBlock *CB, 532 const CoreEngine &CE) { 533 534 CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis(); 535 536 // Test for reachability from any aborted blocks to this block 537 typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; 538 for (AbortedIterator I = CE.blocks_aborted_begin(), 539 E = CE.blocks_aborted_end(); I != E; ++I) { 540 const BlockEdge &BE = I->first; 541 542 // The destination block on the BlockEdge is the first block that was not 543 // analyzed. If we can reach this block from the aborted block, then this 544 // block was not completely analyzed. 545 // 546 // Also explicitly check if the current block is the destination block. 547 // While technically reachable, it means we aborted the analysis on 548 // a path that included that block. 549 const CFGBlock *destBlock = BE.getDst(); 550 if (destBlock == CB || CRA->isReachable(destBlock, CB)) 551 return false; 552 } 553 554 // For the items still on the worklist, see if they are in blocks that 555 // can eventually reach 'CB'. 556 class VisitWL : public WorkList::Visitor { 557 const CFGStmtMap *CBM; 558 const CFGBlock *TargetBlock; 559 CFGReachabilityAnalysis &CRA; 560 public: 561 VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock, 562 CFGReachabilityAnalysis &cra) 563 : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {} 564 virtual bool visit(const WorkListUnit &U) { 565 ProgramPoint P = U.getNode()->getLocation(); 566 const CFGBlock *B = 0; 567 if (StmtPoint *SP = dyn_cast<StmtPoint>(&P)) { 568 B = CBM->getBlock(SP->getStmt()); 569 } 570 else if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 571 B = BE->getDst(); 572 } 573 else if (BlockEntrance *BEnt = dyn_cast<BlockEntrance>(&P)) { 574 B = BEnt->getBlock(); 575 } 576 else if (BlockExit *BExit = dyn_cast<BlockExit>(&P)) { 577 B = BExit->getBlock(); 578 } 579 if (!B) 580 return true; 581 582 return CRA.isReachable(B, TargetBlock); 583 } 584 }; 585 VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA); 586 // Were there any items in the worklist that could potentially reach 587 // this block? 588 if (CE.getWorkList()->visitItemsInWorkList(visitWL)) 589 return false; 590 591 // Verify that this block is reachable from the entry block 592 if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB)) 593 return false; 594 595 // If we get to this point, there is no connection to the entry block or an 596 // aborted block. This path is unreachable and we can report the error. 597 return true; 598} 599 600// Recursive function that determines whether an expression contains any element 601// that varies. This could be due to a compile-time constant like sizeof. An 602// expression may also involve a variable that behaves like a constant. The 603// function returns true if the expression varies, and false otherwise. 604bool IdempotentOperationChecker::CanVary(const Expr *Ex, 605 AnalysisContext *AC) { 606 // Parentheses and casts are irrelevant here 607 Ex = Ex->IgnoreParenCasts(); 608 609 if (Ex->getLocStart().isMacroID()) 610 return false; 611 612 switch (Ex->getStmtClass()) { 613 // Trivially true cases 614 case Stmt::ArraySubscriptExprClass: 615 case Stmt::MemberExprClass: 616 case Stmt::StmtExprClass: 617 case Stmt::CallExprClass: 618 case Stmt::VAArgExprClass: 619 case Stmt::ShuffleVectorExprClass: 620 return true; 621 default: 622 return true; 623 624 // Trivially false cases 625 case Stmt::IntegerLiteralClass: 626 case Stmt::CharacterLiteralClass: 627 case Stmt::FloatingLiteralClass: 628 case Stmt::PredefinedExprClass: 629 case Stmt::ImaginaryLiteralClass: 630 case Stmt::StringLiteralClass: 631 case Stmt::OffsetOfExprClass: 632 case Stmt::CompoundLiteralExprClass: 633 case Stmt::AddrLabelExprClass: 634 case Stmt::BinaryTypeTraitExprClass: 635 case Stmt::GNUNullExprClass: 636 case Stmt::InitListExprClass: 637 case Stmt::DesignatedInitExprClass: 638 case Stmt::BlockExprClass: 639 case Stmt::BlockDeclRefExprClass: 640 return false; 641 642 // Cases requiring custom logic 643 case Stmt::UnaryExprOrTypeTraitExprClass: { 644 const UnaryExprOrTypeTraitExpr *SE = 645 cast<const UnaryExprOrTypeTraitExpr>(Ex); 646 if (SE->getKind() != UETT_SizeOf) 647 return false; 648 return SE->getTypeOfArgument()->isVariableArrayType(); 649 } 650 case Stmt::DeclRefExprClass: 651 // Check for constants/pseudoconstants 652 return !isConstantOrPseudoConstant(cast<DeclRefExpr>(Ex), AC); 653 654 // The next cases require recursion for subexpressions 655 case Stmt::BinaryOperatorClass: { 656 const BinaryOperator *B = cast<const BinaryOperator>(Ex); 657 658 // Exclude cases involving pointer arithmetic. These are usually 659 // false positives. 660 if (B->getOpcode() == BO_Sub || B->getOpcode() == BO_Add) 661 if (B->getLHS()->getType()->getAs<PointerType>()) 662 return false; 663 664 return CanVary(B->getRHS(), AC) 665 || CanVary(B->getLHS(), AC); 666 } 667 case Stmt::UnaryOperatorClass: { 668 const UnaryOperator *U = cast<const UnaryOperator>(Ex); 669 // Handle trivial case first 670 switch (U->getOpcode()) { 671 case UO_Extension: 672 return false; 673 default: 674 return CanVary(U->getSubExpr(), AC); 675 } 676 } 677 case Stmt::ChooseExprClass: 678 return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr( 679 AC->getASTContext()), AC); 680 case Stmt::ConditionalOperatorClass: 681 case Stmt::BinaryConditionalOperatorClass: 682 return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC); 683 } 684} 685 686// Returns true if a DeclRefExpr is or behaves like a constant. 687bool IdempotentOperationChecker::isConstantOrPseudoConstant( 688 const DeclRefExpr *DR, 689 AnalysisContext *AC) { 690 // Check if the type of the Decl is const-qualified 691 if (DR->getType().isConstQualified()) 692 return true; 693 694 // Check for an enum 695 if (isa<EnumConstantDecl>(DR->getDecl())) 696 return true; 697 698 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 699 if (!VD) 700 return true; 701 702 // Check if the Decl behaves like a constant. This check also takes care of 703 // static variables, which can only change between function calls if they are 704 // modified in the AST. 705 PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis(); 706 if (PCA->isPseudoConstant(VD)) 707 return true; 708 709 return false; 710} 711 712// Recursively find any substatements containing VarDecl's with storage other 713// than local 714bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) { 715 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S); 716 717 if (DR) 718 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) 719 if (!VD->hasLocalStorage()) 720 return true; 721 722 for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); 723 ++I) 724 if (const Stmt *child = *I) 725 if (containsNonLocalVarDecl(child)) 726 return true; 727 728 return false; 729} 730 731 732void ento::registerIdempotentOperationChecker(CheckerManager &mgr) { 733 mgr.registerChecker<IdempotentOperationChecker>(); 734} 735