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