10b57cec5SDimitry Andric //== IdenticalExprChecker.cpp - Identical expression checker----------------==// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This defines IdenticalExprChecker, a check that warns about 110b57cec5SDimitry Andric /// unintended use of identical expressions. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric /// It checks for use of identical expressions with comparison operators and 140b57cec5SDimitry Andric /// inside conditional expressions. 150b57cec5SDimitry Andric /// 160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 190b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace clang; 260b57cec5SDimitry Andric using namespace ento; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 290b57cec5SDimitry Andric const Stmt *Stmt2, bool IgnoreSideEffects = false); 300b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 310b57cec5SDimitry Andric // FindIdenticalExprVisitor - Identify nodes using identical expressions. 320b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric namespace { 350b57cec5SDimitry Andric class FindIdenticalExprVisitor 360b57cec5SDimitry Andric : public RecursiveASTVisitor<FindIdenticalExprVisitor> { 370b57cec5SDimitry Andric BugReporter &BR; 380b57cec5SDimitry Andric const CheckerBase *Checker; 390b57cec5SDimitry Andric AnalysisDeclContext *AC; 400b57cec5SDimitry Andric public: 410b57cec5SDimitry Andric explicit FindIdenticalExprVisitor(BugReporter &B, 420b57cec5SDimitry Andric const CheckerBase *Checker, 430b57cec5SDimitry Andric AnalysisDeclContext *A) 440b57cec5SDimitry Andric : BR(B), Checker(Checker), AC(A) {} 450b57cec5SDimitry Andric // FindIdenticalExprVisitor only visits nodes 460b57cec5SDimitry Andric // that are binary operators, if statements or 470b57cec5SDimitry Andric // conditional operators. 480b57cec5SDimitry Andric bool VisitBinaryOperator(const BinaryOperator *B); 490b57cec5SDimitry Andric bool VisitIfStmt(const IfStmt *I); 500b57cec5SDimitry Andric bool VisitConditionalOperator(const ConditionalOperator *C); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric private: 530b57cec5SDimitry Andric void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise, 540b57cec5SDimitry Andric ArrayRef<SourceRange> Sr); 550b57cec5SDimitry Andric void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise); 560b57cec5SDimitry Andric void checkComparisonOp(const BinaryOperator *B); 570b57cec5SDimitry Andric }; 580b57cec5SDimitry Andric } // end anonymous namespace 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B, 610b57cec5SDimitry Andric bool CheckBitwise, 620b57cec5SDimitry Andric ArrayRef<SourceRange> Sr) { 630b57cec5SDimitry Andric StringRef Message; 640b57cec5SDimitry Andric if (CheckBitwise) 650b57cec5SDimitry Andric Message = "identical expressions on both sides of bitwise operator"; 660b57cec5SDimitry Andric else 670b57cec5SDimitry Andric Message = "identical expressions on both sides of logical operator"; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric PathDiagnosticLocation ELoc = 700b57cec5SDimitry Andric PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 710b57cec5SDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker, 720b57cec5SDimitry Andric "Use of identical expressions", 730b57cec5SDimitry Andric categories::LogicError, 740b57cec5SDimitry Andric Message, ELoc, Sr); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B, 780b57cec5SDimitry Andric bool CheckBitwise) { 790b57cec5SDimitry Andric SourceRange Sr[2]; 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric const Expr *LHS = B->getLHS(); 820b57cec5SDimitry Andric const Expr *RHS = B->getRHS(); 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric // Split operators as long as we still have operators to split on. We will 850b57cec5SDimitry Andric // get called for every binary operator in an expression so there is no need 860b57cec5SDimitry Andric // to check every one against each other here, just the right most one with 870b57cec5SDimitry Andric // the others. 880b57cec5SDimitry Andric while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) { 890b57cec5SDimitry Andric if (B->getOpcode() != B2->getOpcode()) 900b57cec5SDimitry Andric break; 910b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) { 920b57cec5SDimitry Andric Sr[0] = RHS->getSourceRange(); 930b57cec5SDimitry Andric Sr[1] = B2->getRHS()->getSourceRange(); 940b57cec5SDimitry Andric reportIdenticalExpr(B, CheckBitwise, Sr); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric LHS = B2->getLHS(); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) { 1000b57cec5SDimitry Andric Sr[0] = RHS->getSourceRange(); 1010b57cec5SDimitry Andric Sr[1] = LHS->getSourceRange(); 1020b57cec5SDimitry Andric reportIdenticalExpr(B, CheckBitwise, Sr); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) { 1070b57cec5SDimitry Andric const Stmt *Stmt1 = I->getThen(); 1080b57cec5SDimitry Andric const Stmt *Stmt2 = I->getElse(); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Check for identical inner condition: 1110b57cec5SDimitry Andric // 1120b57cec5SDimitry Andric // if (x<10) { 1130b57cec5SDimitry Andric // if (x<10) { 1140b57cec5SDimitry Andric // .. 1150b57cec5SDimitry Andric if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) { 1160b57cec5SDimitry Andric if (!CS->body_empty()) { 1170b57cec5SDimitry Andric const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin()); 1180b57cec5SDimitry Andric if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*IgnoreSideEffects=*/ false)) { 1190b57cec5SDimitry Andric PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC); 1200b57cec5SDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions", 1210b57cec5SDimitry Andric categories::LogicError, 1220b57cec5SDimitry Andric "conditions of the inner and outer statements are identical", 1230b57cec5SDimitry Andric ELoc); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric // Check for identical conditions: 1290b57cec5SDimitry Andric // 1300b57cec5SDimitry Andric // if (b) { 1310b57cec5SDimitry Andric // foo1(); 1320b57cec5SDimitry Andric // } else if (b) { 1330b57cec5SDimitry Andric // foo2(); 1340b57cec5SDimitry Andric // } 1350b57cec5SDimitry Andric if (Stmt1 && Stmt2) { 1360b57cec5SDimitry Andric const Expr *Cond1 = I->getCond(); 1370b57cec5SDimitry Andric const Stmt *Else = Stmt2; 1380b57cec5SDimitry Andric while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) { 1390b57cec5SDimitry Andric const Expr *Cond2 = I2->getCond(); 1400b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) { 1410b57cec5SDimitry Andric SourceRange Sr = Cond1->getSourceRange(); 1420b57cec5SDimitry Andric PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC); 1430b57cec5SDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions", 1440b57cec5SDimitry Andric categories::LogicError, 1450b57cec5SDimitry Andric "expression is identical to previous condition", 1460b57cec5SDimitry Andric ELoc, Sr); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric Else = I2->getElse(); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric if (!Stmt1 || !Stmt2) 1530b57cec5SDimitry Andric return true; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Special handling for code like: 1560b57cec5SDimitry Andric // 1570b57cec5SDimitry Andric // if (b) { 1580b57cec5SDimitry Andric // i = 1; 1590b57cec5SDimitry Andric // } else 1600b57cec5SDimitry Andric // i = 1; 1610b57cec5SDimitry Andric if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) { 1620b57cec5SDimitry Andric if (CompStmt->size() == 1) 1630b57cec5SDimitry Andric Stmt1 = CompStmt->body_back(); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) { 1660b57cec5SDimitry Andric if (CompStmt->size() == 1) 1670b57cec5SDimitry Andric Stmt2 = CompStmt->body_back(); 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) { 1710b57cec5SDimitry Andric PathDiagnosticLocation ELoc = 1720b57cec5SDimitry Andric PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC); 1730b57cec5SDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker, 1740b57cec5SDimitry Andric "Identical branches", 1750b57cec5SDimitry Andric categories::LogicError, 1760b57cec5SDimitry Andric "true and false branches are identical", ELoc); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric return true; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { 1820b57cec5SDimitry Andric BinaryOperator::Opcode Op = B->getOpcode(); 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric if (BinaryOperator::isBitwiseOp(Op)) 1850b57cec5SDimitry Andric checkBitwiseOrLogicalOp(B, true); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric if (BinaryOperator::isLogicalOp(Op)) 1880b57cec5SDimitry Andric checkBitwiseOrLogicalOp(B, false); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric if (BinaryOperator::isComparisonOp(Op)) 1910b57cec5SDimitry Andric checkComparisonOp(B); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // We want to visit ALL nodes (subexpressions of binary comparison 1940b57cec5SDimitry Andric // expressions too) that contains comparison operators. 1950b57cec5SDimitry Andric // True is always returned to traverse ALL nodes. 1960b57cec5SDimitry Andric return true; 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) { 2000b57cec5SDimitry Andric BinaryOperator::Opcode Op = B->getOpcode(); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric // 2030b57cec5SDimitry Andric // Special case for floating-point representation. 2040b57cec5SDimitry Andric // 2050b57cec5SDimitry Andric // If expressions on both sides of comparison operator are of type float, 2060b57cec5SDimitry Andric // then for some comparison operators no warning shall be 2070b57cec5SDimitry Andric // reported even if the expressions are identical from a symbolic point of 2080b57cec5SDimitry Andric // view. Comparison between expressions, declared variables and literals 2090b57cec5SDimitry Andric // are treated differently. 2100b57cec5SDimitry Andric // 2110b57cec5SDimitry Andric // != and == between float literals that have the same value should NOT warn. 2120b57cec5SDimitry Andric // < > between float literals that have the same value SHOULD warn. 2130b57cec5SDimitry Andric // 2140b57cec5SDimitry Andric // != and == between the same float declaration should NOT warn. 2150b57cec5SDimitry Andric // < > between the same float declaration SHOULD warn. 2160b57cec5SDimitry Andric // 2170b57cec5SDimitry Andric // != and == between eq. expressions that evaluates into float 2180b57cec5SDimitry Andric // should NOT warn. 2190b57cec5SDimitry Andric // < > between eq. expressions that evaluates into float 2200b57cec5SDimitry Andric // should NOT warn. 2210b57cec5SDimitry Andric // 2220b57cec5SDimitry Andric const Expr *LHS = B->getLHS()->IgnoreParenImpCasts(); 2230b57cec5SDimitry Andric const Expr *RHS = B->getRHS()->IgnoreParenImpCasts(); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS); 2260b57cec5SDimitry Andric const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS); 2270b57cec5SDimitry Andric const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS); 2280b57cec5SDimitry Andric const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS); 2290b57cec5SDimitry Andric if ((DeclRef1) && (DeclRef2)) { 2300b57cec5SDimitry Andric if ((DeclRef1->getType()->hasFloatingRepresentation()) && 2310b57cec5SDimitry Andric (DeclRef2->getType()->hasFloatingRepresentation())) { 2320b57cec5SDimitry Andric if (DeclRef1->getDecl() == DeclRef2->getDecl()) { 2330b57cec5SDimitry Andric if ((Op == BO_EQ) || (Op == BO_NE)) { 2340b57cec5SDimitry Andric return; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric } else if ((FloatLit1) && (FloatLit2)) { 2390b57cec5SDimitry Andric if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) { 2400b57cec5SDimitry Andric if ((Op == BO_EQ) || (Op == BO_NE)) { 2410b57cec5SDimitry Andric return; 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric } else if (LHS->getType()->hasFloatingRepresentation()) { 2450b57cec5SDimitry Andric // If any side of comparison operator still has floating-point 2460b57cec5SDimitry Andric // representation, then it's an expression. Don't warn. 2470b57cec5SDimitry Andric // Here only LHS is checked since RHS will be implicit casted to float. 2480b57cec5SDimitry Andric return; 2490b57cec5SDimitry Andric } else { 2500b57cec5SDimitry Andric // No special case with floating-point representation, report as usual. 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) { 2540b57cec5SDimitry Andric PathDiagnosticLocation ELoc = 2550b57cec5SDimitry Andric PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 2560b57cec5SDimitry Andric StringRef Message; 2570b57cec5SDimitry Andric if (Op == BO_Cmp) 2580b57cec5SDimitry Andric Message = "comparison of identical expressions always evaluates to " 2590b57cec5SDimitry Andric "'equal'"; 2600b57cec5SDimitry Andric else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) 2610b57cec5SDimitry Andric Message = "comparison of identical expressions always evaluates to true"; 2620b57cec5SDimitry Andric else 2630b57cec5SDimitry Andric Message = "comparison of identical expressions always evaluates to false"; 2640b57cec5SDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker, 2650b57cec5SDimitry Andric "Compare of identical expressions", 2660b57cec5SDimitry Andric categories::LogicError, Message, ELoc); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric bool FindIdenticalExprVisitor::VisitConditionalOperator( 2710b57cec5SDimitry Andric const ConditionalOperator *C) { 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric // Check if expressions in conditional expression are identical 2740b57cec5SDimitry Andric // from a symbolic point of view. 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(), 2770b57cec5SDimitry Andric C->getFalseExpr(), true)) { 2780b57cec5SDimitry Andric PathDiagnosticLocation ELoc = 2790b57cec5SDimitry Andric PathDiagnosticLocation::createConditionalColonLoc( 2800b57cec5SDimitry Andric C, BR.getSourceManager()); 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric SourceRange Sr[2]; 2830b57cec5SDimitry Andric Sr[0] = C->getTrueExpr()->getSourceRange(); 2840b57cec5SDimitry Andric Sr[1] = C->getFalseExpr()->getSourceRange(); 2850b57cec5SDimitry Andric BR.EmitBasicReport( 2860b57cec5SDimitry Andric AC->getDecl(), Checker, 2870b57cec5SDimitry Andric "Identical expressions in conditional expression", 2880b57cec5SDimitry Andric categories::LogicError, 2890b57cec5SDimitry Andric "identical expressions on both sides of ':' in conditional expression", 2900b57cec5SDimitry Andric ELoc, Sr); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric // We want to visit ALL nodes (expressions in conditional 2930b57cec5SDimitry Andric // expressions too) that contains conditional operators, 2940b57cec5SDimitry Andric // thus always return true to traverse ALL nodes. 2950b57cec5SDimitry Andric return true; 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric /// Determines whether two statement trees are identical regarding 2990b57cec5SDimitry Andric /// operators and symbols. 3000b57cec5SDimitry Andric /// 3010b57cec5SDimitry Andric /// Exceptions: expressions containing macros or functions with possible side 3020b57cec5SDimitry Andric /// effects are never considered identical. 3030b57cec5SDimitry Andric /// Limitations: (t + u) and (u + t) are not considered identical. 3040b57cec5SDimitry Andric /// t*(u + t) and t*u + t*t are not considered identical. 3050b57cec5SDimitry Andric /// 3060b57cec5SDimitry Andric static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, 3070b57cec5SDimitry Andric const Stmt *Stmt2, bool IgnoreSideEffects) { 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric if (!Stmt1 || !Stmt2) { 3100b57cec5SDimitry Andric return !Stmt1 && !Stmt2; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric // If Stmt1 & Stmt2 are of different class then they are not 3140b57cec5SDimitry Andric // identical statements. 3150b57cec5SDimitry Andric if (Stmt1->getStmtClass() != Stmt2->getStmtClass()) 3160b57cec5SDimitry Andric return false; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric const Expr *Expr1 = dyn_cast<Expr>(Stmt1); 3190b57cec5SDimitry Andric const Expr *Expr2 = dyn_cast<Expr>(Stmt2); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric if (Expr1 && Expr2) { 3220b57cec5SDimitry Andric // If Stmt1 has side effects then don't warn even if expressions 3230b57cec5SDimitry Andric // are identical. 3240b57cec5SDimitry Andric if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx)) 3250b57cec5SDimitry Andric return false; 3260b57cec5SDimitry Andric // If either expression comes from a macro then don't warn even if 3270b57cec5SDimitry Andric // the expressions are identical. 3280b57cec5SDimitry Andric if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) 3290b57cec5SDimitry Andric return false; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric // If all children of two expressions are identical, return true. 3320b57cec5SDimitry Andric Expr::const_child_iterator I1 = Expr1->child_begin(); 3330b57cec5SDimitry Andric Expr::const_child_iterator I2 = Expr2->child_begin(); 3340b57cec5SDimitry Andric while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { 3350b57cec5SDimitry Andric if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric ++I1; 3380b57cec5SDimitry Andric ++I2; 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric // If there are different number of children in the statements, return 3410b57cec5SDimitry Andric // false. 3420b57cec5SDimitry Andric if (I1 != Expr1->child_end()) 3430b57cec5SDimitry Andric return false; 3440b57cec5SDimitry Andric if (I2 != Expr2->child_end()) 3450b57cec5SDimitry Andric return false; 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric switch (Stmt1->getStmtClass()) { 3490b57cec5SDimitry Andric default: 3500b57cec5SDimitry Andric return false; 3510b57cec5SDimitry Andric case Stmt::CallExprClass: 3520b57cec5SDimitry Andric case Stmt::ArraySubscriptExprClass: 3530b57cec5SDimitry Andric case Stmt::OMPArraySectionExprClass: 354*5ffd83dbSDimitry Andric case Stmt::OMPArrayShapingExprClass: 355*5ffd83dbSDimitry Andric case Stmt::OMPIteratorExprClass: 3560b57cec5SDimitry Andric case Stmt::ImplicitCastExprClass: 3570b57cec5SDimitry Andric case Stmt::ParenExprClass: 3580b57cec5SDimitry Andric case Stmt::BreakStmtClass: 3590b57cec5SDimitry Andric case Stmt::ContinueStmtClass: 3600b57cec5SDimitry Andric case Stmt::NullStmtClass: 3610b57cec5SDimitry Andric return true; 3620b57cec5SDimitry Andric case Stmt::CStyleCastExprClass: { 3630b57cec5SDimitry Andric const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1); 3640b57cec5SDimitry Andric const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2); 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten(); 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric case Stmt::ReturnStmtClass: { 3690b57cec5SDimitry Andric const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1); 3700b57cec5SDimitry Andric const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(), 3730b57cec5SDimitry Andric ReturnStmt2->getRetValue(), IgnoreSideEffects); 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric case Stmt::ForStmtClass: { 3760b57cec5SDimitry Andric const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1); 3770b57cec5SDimitry Andric const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(), 3800b57cec5SDimitry Andric IgnoreSideEffects)) 3810b57cec5SDimitry Andric return false; 3820b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(), 3830b57cec5SDimitry Andric IgnoreSideEffects)) 3840b57cec5SDimitry Andric return false; 3850b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(), 3860b57cec5SDimitry Andric IgnoreSideEffects)) 3870b57cec5SDimitry Andric return false; 3880b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(), 3890b57cec5SDimitry Andric IgnoreSideEffects)) 3900b57cec5SDimitry Andric return false; 3910b57cec5SDimitry Andric return true; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric case Stmt::DoStmtClass: { 3940b57cec5SDimitry Andric const DoStmt *DStmt1 = cast<DoStmt>(Stmt1); 3950b57cec5SDimitry Andric const DoStmt *DStmt2 = cast<DoStmt>(Stmt2); 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(), 3980b57cec5SDimitry Andric IgnoreSideEffects)) 3990b57cec5SDimitry Andric return false; 4000b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(), 4010b57cec5SDimitry Andric IgnoreSideEffects)) 4020b57cec5SDimitry Andric return false; 4030b57cec5SDimitry Andric return true; 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric case Stmt::WhileStmtClass: { 4060b57cec5SDimitry Andric const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1); 4070b57cec5SDimitry Andric const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(), 4100b57cec5SDimitry Andric IgnoreSideEffects)) 4110b57cec5SDimitry Andric return false; 4120b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(), 4130b57cec5SDimitry Andric IgnoreSideEffects)) 4140b57cec5SDimitry Andric return false; 4150b57cec5SDimitry Andric return true; 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric case Stmt::IfStmtClass: { 4180b57cec5SDimitry Andric const IfStmt *IStmt1 = cast<IfStmt>(Stmt1); 4190b57cec5SDimitry Andric const IfStmt *IStmt2 = cast<IfStmt>(Stmt2); 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(), 4220b57cec5SDimitry Andric IgnoreSideEffects)) 4230b57cec5SDimitry Andric return false; 4240b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(), 4250b57cec5SDimitry Andric IgnoreSideEffects)) 4260b57cec5SDimitry Andric return false; 4270b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(), 4280b57cec5SDimitry Andric IgnoreSideEffects)) 4290b57cec5SDimitry Andric return false; 4300b57cec5SDimitry Andric return true; 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric case Stmt::CompoundStmtClass: { 4330b57cec5SDimitry Andric const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1); 4340b57cec5SDimitry Andric const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2); 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric if (CompStmt1->size() != CompStmt2->size()) 4370b57cec5SDimitry Andric return false; 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin(); 4400b57cec5SDimitry Andric CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin(); 4410b57cec5SDimitry Andric while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) { 4420b57cec5SDimitry Andric if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) 4430b57cec5SDimitry Andric return false; 4440b57cec5SDimitry Andric ++I1; 4450b57cec5SDimitry Andric ++I2; 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric return true; 4490b57cec5SDimitry Andric } 4500b57cec5SDimitry Andric case Stmt::CompoundAssignOperatorClass: 4510b57cec5SDimitry Andric case Stmt::BinaryOperatorClass: { 4520b57cec5SDimitry Andric const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1); 4530b57cec5SDimitry Andric const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2); 4540b57cec5SDimitry Andric return BinOp1->getOpcode() == BinOp2->getOpcode(); 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric case Stmt::CharacterLiteralClass: { 4570b57cec5SDimitry Andric const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1); 4580b57cec5SDimitry Andric const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2); 4590b57cec5SDimitry Andric return CharLit1->getValue() == CharLit2->getValue(); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric case Stmt::DeclRefExprClass: { 4620b57cec5SDimitry Andric const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1); 4630b57cec5SDimitry Andric const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2); 4640b57cec5SDimitry Andric return DeclRef1->getDecl() == DeclRef2->getDecl(); 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric case Stmt::IntegerLiteralClass: { 4670b57cec5SDimitry Andric const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1); 4680b57cec5SDimitry Andric const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric llvm::APInt I1 = IntLit1->getValue(); 4710b57cec5SDimitry Andric llvm::APInt I2 = IntLit2->getValue(); 4720b57cec5SDimitry Andric if (I1.getBitWidth() != I2.getBitWidth()) 4730b57cec5SDimitry Andric return false; 4740b57cec5SDimitry Andric return I1 == I2; 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric case Stmt::FloatingLiteralClass: { 4770b57cec5SDimitry Andric const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1); 4780b57cec5SDimitry Andric const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2); 4790b57cec5SDimitry Andric return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric case Stmt::StringLiteralClass: { 4820b57cec5SDimitry Andric const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1); 4830b57cec5SDimitry Andric const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2); 4840b57cec5SDimitry Andric return StringLit1->getBytes() == StringLit2->getBytes(); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric case Stmt::MemberExprClass: { 4870b57cec5SDimitry Andric const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1); 4880b57cec5SDimitry Andric const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2); 4890b57cec5SDimitry Andric return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl(); 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric case Stmt::UnaryOperatorClass: { 4920b57cec5SDimitry Andric const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1); 4930b57cec5SDimitry Andric const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2); 4940b57cec5SDimitry Andric return UnaryOp1->getOpcode() == UnaryOp2->getOpcode(); 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5000b57cec5SDimitry Andric // FindIdenticalExprChecker 5010b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric namespace { 5040b57cec5SDimitry Andric class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> { 5050b57cec5SDimitry Andric public: 5060b57cec5SDimitry Andric void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, 5070b57cec5SDimitry Andric BugReporter &BR) const { 5080b57cec5SDimitry Andric FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); 5090b57cec5SDimitry Andric Visitor.TraverseDecl(const_cast<Decl *>(D)); 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric }; 5120b57cec5SDimitry Andric } // end anonymous namespace 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric void ento::registerIdenticalExprChecker(CheckerManager &Mgr) { 5150b57cec5SDimitry Andric Mgr.registerChecker<FindIdenticalExprChecker>(); 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 518*5ffd83dbSDimitry Andric bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) { 5190b57cec5SDimitry Andric return true; 5200b57cec5SDimitry Andric } 521