1//== IdenticalExprChecker.cpp - Identical expression checker----------------==// 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/// \file 11/// \brief This defines IdenticalExprChecker, a check that warns about 12/// unintended use of identical expressions. 13/// 14/// It checks for use of identical expressions with comparison operators and 15/// inside conditional expressions. 16/// 17//===----------------------------------------------------------------------===// 18 19#include "ClangSACheckers.h" 20#include "clang/AST/RecursiveASTVisitor.h" 21#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22#include "clang/StaticAnalyzer/Core/Checker.h" 23#include "clang/StaticAnalyzer/Core/CheckerManager.h" 24#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25 26using namespace clang; 27using namespace ento; 28 29static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 30 const Stmt *Stmt2, bool IgnoreSideEffects = false); 31//===----------------------------------------------------------------------===// 32// FindIdenticalExprVisitor - Identify nodes using identical expressions. 33//===----------------------------------------------------------------------===// 34 35namespace { 36class FindIdenticalExprVisitor 37 : public RecursiveASTVisitor<FindIdenticalExprVisitor> { 38 BugReporter &BR; 39 const CheckerBase *Checker; 40 AnalysisDeclContext *AC; 41public: 42 explicit FindIdenticalExprVisitor(BugReporter &B, 43 const CheckerBase *Checker, 44 AnalysisDeclContext *A) 45 : BR(B), Checker(Checker), AC(A) {} 46 // FindIdenticalExprVisitor only visits nodes 47 // that are binary operators, if statements or 48 // conditional operators. 49 bool VisitBinaryOperator(const BinaryOperator *B); 50 bool VisitIfStmt(const IfStmt *I); 51 bool VisitConditionalOperator(const ConditionalOperator *C); 52 53private: 54 void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise, 55 ArrayRef<SourceRange> Sr); 56 void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise); 57 void checkComparisonOp(const BinaryOperator *B); 58}; 59} // end anonymous namespace 60 61void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B, 62 bool CheckBitwise, 63 ArrayRef<SourceRange> Sr) { 64 StringRef Message; 65 if (CheckBitwise) 66 Message = "identical expressions on both sides of bitwise operator"; 67 else 68 Message = "identical expressions on both sides of logical operator"; 69 70 PathDiagnosticLocation ELoc = 71 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 72 BR.EmitBasicReport(AC->getDecl(), Checker, 73 "Use of identical expressions", 74 categories::LogicError, 75 Message, ELoc, Sr); 76} 77 78void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B, 79 bool CheckBitwise) { 80 SourceRange Sr[2]; 81 82 const Expr *LHS = B->getLHS(); 83 const Expr *RHS = B->getRHS(); 84 85 // Split operators as long as we still have operators to split on. We will 86 // get called for every binary operator in an expression so there is no need 87 // to check every one against each other here, just the right most one with 88 // the others. 89 while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) { 90 if (B->getOpcode() != B2->getOpcode()) 91 break; 92 if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) { 93 Sr[0] = RHS->getSourceRange(); 94 Sr[1] = B2->getRHS()->getSourceRange(); 95 reportIdenticalExpr(B, CheckBitwise, Sr); 96 } 97 LHS = B2->getLHS(); 98 } 99 100 if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) { 101 Sr[0] = RHS->getSourceRange(); 102 Sr[1] = LHS->getSourceRange(); 103 reportIdenticalExpr(B, CheckBitwise, Sr); 104 } 105} 106 107bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) { 108 const Stmt *Stmt1 = I->getThen(); 109 const Stmt *Stmt2 = I->getElse(); 110 111 // Check for identical inner condition: 112 // 113 // if (x<10) { 114 // if (x<10) { 115 // .. 116 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) { 117 if (!CS->body_empty()) { 118 const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin()); 119 if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*ignoreSideEffects=*/ false)) { 120 PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC); 121 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions", 122 categories::LogicError, 123 "conditions of the inner and outer statements are identical", 124 ELoc); 125 } 126 } 127 } 128 129 // Check for identical conditions: 130 // 131 // if (b) { 132 // foo1(); 133 // } else if (b) { 134 // foo2(); 135 // } 136 if (Stmt1 && Stmt2) { 137 const Expr *Cond1 = I->getCond(); 138 const Stmt *Else = Stmt2; 139 while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) { 140 const Expr *Cond2 = I2->getCond(); 141 if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) { 142 SourceRange Sr = Cond1->getSourceRange(); 143 PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC); 144 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions", 145 categories::LogicError, 146 "expression is identical to previous condition", 147 ELoc, Sr); 148 } 149 Else = I2->getElse(); 150 } 151 } 152 153 if (!Stmt1 || !Stmt2) 154 return true; 155 156 // Special handling for code like: 157 // 158 // if (b) { 159 // i = 1; 160 // } else 161 // i = 1; 162 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) { 163 if (CompStmt->size() == 1) 164 Stmt1 = CompStmt->body_back(); 165 } 166 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) { 167 if (CompStmt->size() == 1) 168 Stmt2 = CompStmt->body_back(); 169 } 170 171 if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) { 172 PathDiagnosticLocation ELoc = 173 PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC); 174 BR.EmitBasicReport(AC->getDecl(), Checker, 175 "Identical branches", 176 categories::LogicError, 177 "true and false branches are identical", ELoc); 178 } 179 return true; 180} 181 182bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { 183 BinaryOperator::Opcode Op = B->getOpcode(); 184 185 if (BinaryOperator::isBitwiseOp(Op)) 186 checkBitwiseOrLogicalOp(B, true); 187 188 if (BinaryOperator::isLogicalOp(Op)) 189 checkBitwiseOrLogicalOp(B, false); 190 191 if (BinaryOperator::isComparisonOp(Op)) 192 checkComparisonOp(B); 193 194 // We want to visit ALL nodes (subexpressions of binary comparison 195 // expressions too) that contains comparison operators. 196 // True is always returned to traverse ALL nodes. 197 return true; 198} 199 200void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) { 201 BinaryOperator::Opcode Op = B->getOpcode(); 202 203 // 204 // Special case for floating-point representation. 205 // 206 // If expressions on both sides of comparison operator are of type float, 207 // then for some comparison operators no warning shall be 208 // reported even if the expressions are identical from a symbolic point of 209 // view. Comparison between expressions, declared variables and literals 210 // are treated differently. 211 // 212 // != and == between float literals that have the same value should NOT warn. 213 // < > between float literals that have the same value SHOULD warn. 214 // 215 // != and == between the same float declaration should NOT warn. 216 // < > between the same float declaration SHOULD warn. 217 // 218 // != and == between eq. expressions that evaluates into float 219 // should NOT warn. 220 // < > between eq. expressions that evaluates into float 221 // should NOT warn. 222 // 223 const Expr *LHS = B->getLHS()->IgnoreParenImpCasts(); 224 const Expr *RHS = B->getRHS()->IgnoreParenImpCasts(); 225 226 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS); 227 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS); 228 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS); 229 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS); 230 if ((DeclRef1) && (DeclRef2)) { 231 if ((DeclRef1->getType()->hasFloatingRepresentation()) && 232 (DeclRef2->getType()->hasFloatingRepresentation())) { 233 if (DeclRef1->getDecl() == DeclRef2->getDecl()) { 234 if ((Op == BO_EQ) || (Op == BO_NE)) { 235 return; 236 } 237 } 238 } 239 } else if ((FloatLit1) && (FloatLit2)) { 240 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) { 241 if ((Op == BO_EQ) || (Op == BO_NE)) { 242 return; 243 } 244 } 245 } else if (LHS->getType()->hasFloatingRepresentation()) { 246 // If any side of comparison operator still has floating-point 247 // representation, then it's an expression. Don't warn. 248 // Here only LHS is checked since RHS will be implicit casted to float. 249 return; 250 } else { 251 // No special case with floating-point representation, report as usual. 252 } 253 254 if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) { 255 PathDiagnosticLocation ELoc = 256 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 257 StringRef Message; 258 if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) 259 Message = "comparison of identical expressions always evaluates to true"; 260 else 261 Message = "comparison of identical expressions always evaluates to false"; 262 BR.EmitBasicReport(AC->getDecl(), Checker, 263 "Compare of identical expressions", 264 categories::LogicError, Message, ELoc); 265 } 266} 267 268bool FindIdenticalExprVisitor::VisitConditionalOperator( 269 const ConditionalOperator *C) { 270 271 // Check if expressions in conditional expression are identical 272 // from a symbolic point of view. 273 274 if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(), 275 C->getFalseExpr(), true)) { 276 PathDiagnosticLocation ELoc = 277 PathDiagnosticLocation::createConditionalColonLoc( 278 C, BR.getSourceManager()); 279 280 SourceRange Sr[2]; 281 Sr[0] = C->getTrueExpr()->getSourceRange(); 282 Sr[1] = C->getFalseExpr()->getSourceRange(); 283 BR.EmitBasicReport( 284 AC->getDecl(), Checker, 285 "Identical expressions in conditional expression", 286 categories::LogicError, 287 "identical expressions on both sides of ':' in conditional expression", 288 ELoc, Sr); 289 } 290 // We want to visit ALL nodes (expressions in conditional 291 // expressions too) that contains conditional operators, 292 // thus always return true to traverse ALL nodes. 293 return true; 294} 295 296/// \brief Determines whether two statement trees are identical regarding 297/// operators and symbols. 298/// 299/// Exceptions: expressions containing macros or functions with possible side 300/// effects are never considered identical. 301/// Limitations: (t + u) and (u + t) are not considered identical. 302/// t*(u + t) and t*u + t*t are not considered identical. 303/// 304static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 305 const Stmt *Stmt2, bool IgnoreSideEffects) { 306 307 if (!Stmt1 || !Stmt2) { 308 return !Stmt1 && !Stmt2; 309 } 310 311 // If Stmt1 & Stmt2 are of different class then they are not 312 // identical statements. 313 if (Stmt1->getStmtClass() != Stmt2->getStmtClass()) 314 return false; 315 316 const Expr *Expr1 = dyn_cast<Expr>(Stmt1); 317 const Expr *Expr2 = dyn_cast<Expr>(Stmt2); 318 319 if (Expr1 && Expr2) { 320 // If Stmt1 has side effects then don't warn even if expressions 321 // are identical. 322 if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx)) 323 return false; 324 // If either expression comes from a macro then don't warn even if 325 // the expressions are identical. 326 if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) 327 return false; 328 329 // If all children of two expressions are identical, return true. 330 Expr::const_child_iterator I1 = Expr1->child_begin(); 331 Expr::const_child_iterator I2 = Expr2->child_begin(); 332 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { 333 if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 334 return false; 335 ++I1; 336 ++I2; 337 } 338 // If there are different number of children in the statements, return 339 // false. 340 if (I1 != Expr1->child_end()) 341 return false; 342 if (I2 != Expr2->child_end()) 343 return false; 344 } 345 346 switch (Stmt1->getStmtClass()) { 347 default: 348 return false; 349 case Stmt::CallExprClass: 350 case Stmt::ArraySubscriptExprClass: 351 case Stmt::OMPArraySectionExprClass: 352 case Stmt::ImplicitCastExprClass: 353 case Stmt::ParenExprClass: 354 case Stmt::BreakStmtClass: 355 case Stmt::ContinueStmtClass: 356 case Stmt::NullStmtClass: 357 return true; 358 case Stmt::CStyleCastExprClass: { 359 const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1); 360 const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2); 361 362 return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten(); 363 } 364 case Stmt::ReturnStmtClass: { 365 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1); 366 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2); 367 368 return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(), 369 ReturnStmt2->getRetValue(), IgnoreSideEffects); 370 } 371 case Stmt::ForStmtClass: { 372 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1); 373 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2); 374 375 if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(), 376 IgnoreSideEffects)) 377 return false; 378 if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(), 379 IgnoreSideEffects)) 380 return false; 381 if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(), 382 IgnoreSideEffects)) 383 return false; 384 if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(), 385 IgnoreSideEffects)) 386 return false; 387 return true; 388 } 389 case Stmt::DoStmtClass: { 390 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1); 391 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2); 392 393 if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(), 394 IgnoreSideEffects)) 395 return false; 396 if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(), 397 IgnoreSideEffects)) 398 return false; 399 return true; 400 } 401 case Stmt::WhileStmtClass: { 402 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1); 403 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2); 404 405 if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(), 406 IgnoreSideEffects)) 407 return false; 408 if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(), 409 IgnoreSideEffects)) 410 return false; 411 return true; 412 } 413 case Stmt::IfStmtClass: { 414 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1); 415 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2); 416 417 if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(), 418 IgnoreSideEffects)) 419 return false; 420 if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(), 421 IgnoreSideEffects)) 422 return false; 423 if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(), 424 IgnoreSideEffects)) 425 return false; 426 return true; 427 } 428 case Stmt::CompoundStmtClass: { 429 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1); 430 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2); 431 432 if (CompStmt1->size() != CompStmt2->size()) 433 return false; 434 435 CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin(); 436 CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin(); 437 while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) { 438 if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 439 return false; 440 ++I1; 441 ++I2; 442 } 443 444 return true; 445 } 446 case Stmt::CompoundAssignOperatorClass: 447 case Stmt::BinaryOperatorClass: { 448 const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1); 449 const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2); 450 return BinOp1->getOpcode() == BinOp2->getOpcode(); 451 } 452 case Stmt::CharacterLiteralClass: { 453 const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1); 454 const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2); 455 return CharLit1->getValue() == CharLit2->getValue(); 456 } 457 case Stmt::DeclRefExprClass: { 458 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1); 459 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2); 460 return DeclRef1->getDecl() == DeclRef2->getDecl(); 461 } 462 case Stmt::IntegerLiteralClass: { 463 const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1); 464 const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2); 465 466 llvm::APInt I1 = IntLit1->getValue(); 467 llvm::APInt I2 = IntLit2->getValue(); 468 if (I1.getBitWidth() != I2.getBitWidth()) 469 return false; 470 return I1 == I2; 471 } 472 case Stmt::FloatingLiteralClass: { 473 const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1); 474 const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2); 475 return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); 476 } 477 case Stmt::StringLiteralClass: { 478 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1); 479 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2); 480 return StringLit1->getBytes() == StringLit2->getBytes(); 481 } 482 case Stmt::MemberExprClass: { 483 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1); 484 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2); 485 return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl(); 486 } 487 case Stmt::UnaryOperatorClass: { 488 const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1); 489 const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2); 490 return UnaryOp1->getOpcode() == UnaryOp2->getOpcode(); 491 } 492 } 493} 494 495//===----------------------------------------------------------------------===// 496// FindIdenticalExprChecker 497//===----------------------------------------------------------------------===// 498 499namespace { 500class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> { 501public: 502 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, 503 BugReporter &BR) const { 504 FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); 505 Visitor.TraverseDecl(const_cast<Decl *>(D)); 506 } 507}; 508} // end anonymous namespace 509 510void ento::registerIdenticalExprChecker(CheckerManager &Mgr) { 511 Mgr.registerChecker<FindIdenticalExprChecker>(); 512} 513