151327f92SJordan Rose //== IdenticalExprChecker.cpp - Identical expression checker----------------==//
251327f92SJordan Rose //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
651327f92SJordan Rose //
751327f92SJordan Rose //===----------------------------------------------------------------------===//
851327f92SJordan Rose ///
951327f92SJordan Rose /// \file
109fc8faf9SAdrian Prantl /// This defines IdenticalExprChecker, a check that warns about
1151327f92SJordan Rose /// unintended use of identical expressions.
1251327f92SJordan Rose ///
1360bd88d3SJordan Rose /// It checks for use of identical expressions with comparison operators and
1460bd88d3SJordan Rose /// inside conditional expressions.
1551327f92SJordan Rose ///
1651327f92SJordan Rose //===----------------------------------------------------------------------===//
1751327f92SJordan Rose 
1876a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
195553d0d4SChandler Carruth #include "clang/AST/RecursiveASTVisitor.h"
2051327f92SJordan Rose #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2151327f92SJordan Rose #include "clang/StaticAnalyzer/Core/Checker.h"
2251327f92SJordan Rose #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2351327f92SJordan Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2451327f92SJordan Rose 
2551327f92SJordan Rose using namespace clang;
2651327f92SJordan Rose using namespace ento;
2751327f92SJordan Rose 
2870e7e871SJordan Rose static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
2970e7e871SJordan Rose                             const Stmt *Stmt2, bool IgnoreSideEffects = false);
3051327f92SJordan Rose //===----------------------------------------------------------------------===//
3151327f92SJordan Rose // FindIdenticalExprVisitor - Identify nodes using identical expressions.
3251327f92SJordan Rose //===----------------------------------------------------------------------===//
3351327f92SJordan Rose 
34e8a2c18bSBenjamin Kramer namespace {
3551327f92SJordan Rose class FindIdenticalExprVisitor
3651327f92SJordan Rose     : public RecursiveASTVisitor<FindIdenticalExprVisitor> {
3794008121SJordan Rose   BugReporter &BR;
3894008121SJordan Rose   const CheckerBase *Checker;
3994008121SJordan Rose   AnalysisDeclContext *AC;
4051327f92SJordan Rose public:
FindIdenticalExprVisitor(BugReporter & B,const CheckerBase * Checker,AnalysisDeclContext * A)414aca9b1cSAlexander Kornienko   explicit FindIdenticalExprVisitor(BugReporter &B,
424aca9b1cSAlexander Kornienko                                     const CheckerBase *Checker,
434aca9b1cSAlexander Kornienko                                     AnalysisDeclContext *A)
444aca9b1cSAlexander Kornienko       : BR(B), Checker(Checker), AC(A) {}
4551327f92SJordan Rose   // FindIdenticalExprVisitor only visits nodes
4670e7e871SJordan Rose   // that are binary operators, if statements or
4770e7e871SJordan Rose   // conditional operators.
4851327f92SJordan Rose   bool VisitBinaryOperator(const BinaryOperator *B);
4970e7e871SJordan Rose   bool VisitIfStmt(const IfStmt *I);
5060bd88d3SJordan Rose   bool VisitConditionalOperator(const ConditionalOperator *C);
5151327f92SJordan Rose 
5251327f92SJordan Rose private:
5394008121SJordan Rose   void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
5494008121SJordan Rose                            ArrayRef<SourceRange> Sr);
5594008121SJordan Rose   void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
5694008121SJordan Rose   void checkComparisonOp(const BinaryOperator *B);
5751327f92SJordan Rose };
58e8a2c18bSBenjamin Kramer } // end anonymous namespace
5951327f92SJordan Rose 
reportIdenticalExpr(const BinaryOperator * B,bool CheckBitwise,ArrayRef<SourceRange> Sr)6094008121SJordan Rose void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
6194008121SJordan Rose                                                    bool CheckBitwise,
6294008121SJordan Rose                                                    ArrayRef<SourceRange> Sr) {
6394008121SJordan Rose   StringRef Message;
6494008121SJordan Rose   if (CheckBitwise)
6594008121SJordan Rose     Message = "identical expressions on both sides of bitwise operator";
6694008121SJordan Rose   else
6794008121SJordan Rose     Message = "identical expressions on both sides of logical operator";
6894008121SJordan Rose 
6994008121SJordan Rose   PathDiagnosticLocation ELoc =
7094008121SJordan Rose       PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
7194008121SJordan Rose   BR.EmitBasicReport(AC->getDecl(), Checker,
7294008121SJordan Rose                      "Use of identical expressions",
7394008121SJordan Rose                      categories::LogicError,
7494008121SJordan Rose                      Message, ELoc, Sr);
7594008121SJordan Rose }
7694008121SJordan Rose 
checkBitwiseOrLogicalOp(const BinaryOperator * B,bool CheckBitwise)7794008121SJordan Rose void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
7894008121SJordan Rose                                                        bool CheckBitwise) {
7994008121SJordan Rose   SourceRange Sr[2];
8094008121SJordan Rose 
8194008121SJordan Rose   const Expr *LHS = B->getLHS();
8294008121SJordan Rose   const Expr *RHS = B->getRHS();
8394008121SJordan Rose 
8494008121SJordan Rose   // Split operators as long as we still have operators to split on. We will
8594008121SJordan Rose   // get called for every binary operator in an expression so there is no need
8694008121SJordan Rose   // to check every one against each other here, just the right most one with
8794008121SJordan Rose   // the others.
8894008121SJordan Rose   while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
8994008121SJordan Rose     if (B->getOpcode() != B2->getOpcode())
9094008121SJordan Rose       break;
9194008121SJordan Rose     if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
9294008121SJordan Rose       Sr[0] = RHS->getSourceRange();
9394008121SJordan Rose       Sr[1] = B2->getRHS()->getSourceRange();
9494008121SJordan Rose       reportIdenticalExpr(B, CheckBitwise, Sr);
9594008121SJordan Rose     }
9694008121SJordan Rose     LHS = B2->getLHS();
9794008121SJordan Rose   }
9894008121SJordan Rose 
9994008121SJordan Rose   if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
10094008121SJordan Rose     Sr[0] = RHS->getSourceRange();
10194008121SJordan Rose     Sr[1] = LHS->getSourceRange();
10294008121SJordan Rose     reportIdenticalExpr(B, CheckBitwise, Sr);
10394008121SJordan Rose   }
10494008121SJordan Rose }
10594008121SJordan Rose 
VisitIfStmt(const IfStmt * I)10670e7e871SJordan Rose bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
10770e7e871SJordan Rose   const Stmt *Stmt1 = I->getThen();
10870e7e871SJordan Rose   const Stmt *Stmt2 = I->getElse();
10970e7e871SJordan Rose 
11030e2a44aSDaniel Marjamaki   // Check for identical inner condition:
11130e2a44aSDaniel Marjamaki   //
11230e2a44aSDaniel Marjamaki   // if (x<10) {
11330e2a44aSDaniel Marjamaki   //   if (x<10) {
11430e2a44aSDaniel Marjamaki   //   ..
11530e2a44aSDaniel Marjamaki   if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
11630e2a44aSDaniel Marjamaki     if (!CS->body_empty()) {
11730e2a44aSDaniel Marjamaki       const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
11849a3ad21SRui Ueyama       if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*IgnoreSideEffects=*/ false)) {
11930e2a44aSDaniel Marjamaki         PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC);
12030e2a44aSDaniel Marjamaki         BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
12130e2a44aSDaniel Marjamaki           categories::LogicError,
12230e2a44aSDaniel Marjamaki           "conditions of the inner and outer statements are identical",
12330e2a44aSDaniel Marjamaki           ELoc);
12430e2a44aSDaniel Marjamaki       }
12530e2a44aSDaniel Marjamaki     }
12630e2a44aSDaniel Marjamaki   }
12730e2a44aSDaniel Marjamaki 
128a6839aaaSJordan Rose   // Check for identical conditions:
129a6839aaaSJordan Rose   //
130a6839aaaSJordan Rose   // if (b) {
131a6839aaaSJordan Rose   //   foo1();
132a6839aaaSJordan Rose   // } else if (b) {
133a6839aaaSJordan Rose   //   foo2();
134a6839aaaSJordan Rose   // }
135a6839aaaSJordan Rose   if (Stmt1 && Stmt2) {
136a6839aaaSJordan Rose     const Expr *Cond1 = I->getCond();
137a6839aaaSJordan Rose     const Stmt *Else = Stmt2;
138a6839aaaSJordan Rose     while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
139a6839aaaSJordan Rose       const Expr *Cond2 = I2->getCond();
140a6839aaaSJordan Rose       if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
141a6839aaaSJordan Rose         SourceRange Sr = Cond1->getSourceRange();
142a6839aaaSJordan Rose         PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
143a6839aaaSJordan Rose         BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
144a6839aaaSJordan Rose                            categories::LogicError,
145a6839aaaSJordan Rose                            "expression is identical to previous condition",
146a6839aaaSJordan Rose                            ELoc, Sr);
147a6839aaaSJordan Rose       }
148a6839aaaSJordan Rose       Else = I2->getElse();
149a6839aaaSJordan Rose     }
150a6839aaaSJordan Rose   }
151a6839aaaSJordan Rose 
15270e7e871SJordan Rose   if (!Stmt1 || !Stmt2)
15370e7e871SJordan Rose     return true;
15470e7e871SJordan Rose 
15570e7e871SJordan Rose   // Special handling for code like:
15670e7e871SJordan Rose   //
15770e7e871SJordan Rose   // if (b) {
15870e7e871SJordan Rose   //   i = 1;
15970e7e871SJordan Rose   // } else
16070e7e871SJordan Rose   //   i = 1;
16170e7e871SJordan Rose   if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
16270e7e871SJordan Rose     if (CompStmt->size() == 1)
16370e7e871SJordan Rose       Stmt1 = CompStmt->body_back();
16470e7e871SJordan Rose   }
16570e7e871SJordan Rose   if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
16670e7e871SJordan Rose     if (CompStmt->size() == 1)
16770e7e871SJordan Rose       Stmt2 = CompStmt->body_back();
16870e7e871SJordan Rose   }
16970e7e871SJordan Rose 
17070e7e871SJordan Rose   if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
17170e7e871SJordan Rose       PathDiagnosticLocation ELoc =
17270e7e871SJordan Rose           PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
17370e7e871SJordan Rose       BR.EmitBasicReport(AC->getDecl(), Checker,
17470e7e871SJordan Rose                          "Identical branches",
17570e7e871SJordan Rose                          categories::LogicError,
17670e7e871SJordan Rose                          "true and false branches are identical", ELoc);
17770e7e871SJordan Rose   }
17870e7e871SJordan Rose   return true;
17970e7e871SJordan Rose }
18070e7e871SJordan Rose 
VisitBinaryOperator(const BinaryOperator * B)18151327f92SJordan Rose bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
18251327f92SJordan Rose   BinaryOperator::Opcode Op = B->getOpcode();
18394008121SJordan Rose 
18494008121SJordan Rose   if (BinaryOperator::isBitwiseOp(Op))
18594008121SJordan Rose     checkBitwiseOrLogicalOp(B, true);
18694008121SJordan Rose 
18794008121SJordan Rose   if (BinaryOperator::isLogicalOp(Op))
18894008121SJordan Rose     checkBitwiseOrLogicalOp(B, false);
18994008121SJordan Rose 
19094008121SJordan Rose   if (BinaryOperator::isComparisonOp(Op))
19194008121SJordan Rose     checkComparisonOp(B);
19294008121SJordan Rose 
19394008121SJordan Rose   // We want to visit ALL nodes (subexpressions of binary comparison
19494008121SJordan Rose   // expressions too) that contains comparison operators.
19594008121SJordan Rose   // True is always returned to traverse ALL nodes.
19651327f92SJordan Rose   return true;
19794008121SJordan Rose }
19894008121SJordan Rose 
checkComparisonOp(const BinaryOperator * B)19994008121SJordan Rose void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
20094008121SJordan Rose   BinaryOperator::Opcode Op = B->getOpcode();
20194008121SJordan Rose 
20251327f92SJordan Rose   //
20351327f92SJordan Rose   // Special case for floating-point representation.
20451327f92SJordan Rose   //
20551327f92SJordan Rose   // If expressions on both sides of comparison operator are of type float,
20651327f92SJordan Rose   // then for some comparison operators no warning shall be
20751327f92SJordan Rose   // reported even if the expressions are identical from a symbolic point of
20851327f92SJordan Rose   // view. Comparison between expressions, declared variables and literals
20951327f92SJordan Rose   // are treated differently.
21051327f92SJordan Rose   //
21151327f92SJordan Rose   // != and == between float literals that have the same value should NOT warn.
21251327f92SJordan Rose   // < > between float literals that have the same value SHOULD warn.
21351327f92SJordan Rose   //
21451327f92SJordan Rose   // != and == between the same float declaration should NOT warn.
21551327f92SJordan Rose   // < > between the same float declaration SHOULD warn.
21651327f92SJordan Rose   //
21751327f92SJordan Rose   // != and == between eq. expressions that evaluates into float
21851327f92SJordan Rose   //           should NOT warn.
21951327f92SJordan Rose   // < >       between eq. expressions that evaluates into float
22051327f92SJordan Rose   //           should NOT warn.
22151327f92SJordan Rose   //
22251327f92SJordan Rose   const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
22351327f92SJordan Rose   const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
22451327f92SJordan Rose 
22551327f92SJordan Rose   const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
22651327f92SJordan Rose   const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
22751327f92SJordan Rose   const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
22851327f92SJordan Rose   const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
22951327f92SJordan Rose   if ((DeclRef1) && (DeclRef2)) {
23051327f92SJordan Rose     if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
23151327f92SJordan Rose         (DeclRef2->getType()->hasFloatingRepresentation())) {
23251327f92SJordan Rose       if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
23351327f92SJordan Rose         if ((Op == BO_EQ) || (Op == BO_NE)) {
23494008121SJordan Rose           return;
23551327f92SJordan Rose         }
23651327f92SJordan Rose       }
23751327f92SJordan Rose     }
23851327f92SJordan Rose   } else if ((FloatLit1) && (FloatLit2)) {
23951327f92SJordan Rose     if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
24051327f92SJordan Rose       if ((Op == BO_EQ) || (Op == BO_NE)) {
24194008121SJordan Rose         return;
24251327f92SJordan Rose       }
24351327f92SJordan Rose     }
24451327f92SJordan Rose   } else if (LHS->getType()->hasFloatingRepresentation()) {
24551327f92SJordan Rose     // If any side of comparison operator still has floating-point
24651327f92SJordan Rose     // representation, then it's an expression. Don't warn.
24751327f92SJordan Rose     // Here only LHS is checked since RHS will be implicit casted to float.
24894008121SJordan Rose     return;
24951327f92SJordan Rose   } else {
25051327f92SJordan Rose     // No special case with floating-point representation, report as usual.
25151327f92SJordan Rose   }
25251327f92SJordan Rose 
25370e7e871SJordan Rose   if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
25451327f92SJordan Rose     PathDiagnosticLocation ELoc =
25551327f92SJordan Rose         PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
25651327f92SJordan Rose     StringRef Message;
257c70f1d63SRichard Smith     if (Op == BO_Cmp)
258c70f1d63SRichard Smith       Message = "comparison of identical expressions always evaluates to "
259c70f1d63SRichard Smith                 "'equal'";
260c70f1d63SRichard Smith     else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
26151327f92SJordan Rose       Message = "comparison of identical expressions always evaluates to true";
26251327f92SJordan Rose     else
26351327f92SJordan Rose       Message = "comparison of identical expressions always evaluates to false";
2644aca9b1cSAlexander Kornienko     BR.EmitBasicReport(AC->getDecl(), Checker,
2654aca9b1cSAlexander Kornienko                        "Compare of identical expressions",
26651327f92SJordan Rose                        categories::LogicError, Message, ELoc);
26751327f92SJordan Rose   }
26851327f92SJordan Rose }
26960bd88d3SJordan Rose 
VisitConditionalOperator(const ConditionalOperator * C)27060bd88d3SJordan Rose bool FindIdenticalExprVisitor::VisitConditionalOperator(
27160bd88d3SJordan Rose     const ConditionalOperator *C) {
27260bd88d3SJordan Rose 
27360bd88d3SJordan Rose   // Check if expressions in conditional expression are identical
27460bd88d3SJordan Rose   // from a symbolic point of view.
27560bd88d3SJordan Rose 
27670e7e871SJordan Rose   if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
27760bd88d3SJordan Rose                       C->getFalseExpr(), true)) {
27860bd88d3SJordan Rose     PathDiagnosticLocation ELoc =
27960bd88d3SJordan Rose         PathDiagnosticLocation::createConditionalColonLoc(
28060bd88d3SJordan Rose             C, BR.getSourceManager());
28160bd88d3SJordan Rose 
28260bd88d3SJordan Rose     SourceRange Sr[2];
28360bd88d3SJordan Rose     Sr[0] = C->getTrueExpr()->getSourceRange();
28460bd88d3SJordan Rose     Sr[1] = C->getFalseExpr()->getSourceRange();
28560bd88d3SJordan Rose     BR.EmitBasicReport(
2864aca9b1cSAlexander Kornienko         AC->getDecl(), Checker,
2874aca9b1cSAlexander Kornienko         "Identical expressions in conditional expression",
28860bd88d3SJordan Rose         categories::LogicError,
28960bd88d3SJordan Rose         "identical expressions on both sides of ':' in conditional expression",
29060bd88d3SJordan Rose         ELoc, Sr);
29160bd88d3SJordan Rose   }
29260bd88d3SJordan Rose   // We want to visit ALL nodes (expressions in conditional
29360bd88d3SJordan Rose   // expressions too) that contains conditional operators,
29460bd88d3SJordan Rose   // thus always return true to traverse ALL nodes.
29560bd88d3SJordan Rose   return true;
29660bd88d3SJordan Rose }
29760bd88d3SJordan Rose 
2989fc8faf9SAdrian Prantl /// Determines whether two statement trees are identical regarding
29951327f92SJordan Rose /// operators and symbols.
30051327f92SJordan Rose ///
30151327f92SJordan Rose /// Exceptions: expressions containing macros or functions with possible side
30251327f92SJordan Rose /// effects are never considered identical.
30351327f92SJordan Rose /// Limitations: (t + u) and (u + t) are not considered identical.
30451327f92SJordan Rose /// t*(u + t) and t*u + t*t are not considered identical.
30551327f92SJordan Rose ///
isIdenticalStmt(const ASTContext & Ctx,const Stmt * Stmt1,const Stmt * Stmt2,bool IgnoreSideEffects)30670e7e871SJordan Rose static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
30770e7e871SJordan Rose                             const Stmt *Stmt2, bool IgnoreSideEffects) {
30870e7e871SJordan Rose 
30970e7e871SJordan Rose   if (!Stmt1 || !Stmt2) {
3109c10490eSAlexander Kornienko     return !Stmt1 && !Stmt2;
31170e7e871SJordan Rose   }
31270e7e871SJordan Rose 
31370e7e871SJordan Rose   // If Stmt1 & Stmt2 are of different class then they are not
31470e7e871SJordan Rose   // identical statements.
31570e7e871SJordan Rose   if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
31670e7e871SJordan Rose     return false;
31770e7e871SJordan Rose 
31870e7e871SJordan Rose   const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
31970e7e871SJordan Rose   const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
32070e7e871SJordan Rose 
32170e7e871SJordan Rose   if (Expr1 && Expr2) {
32270e7e871SJordan Rose     // If Stmt1 has side effects then don't warn even if expressions
32351327f92SJordan Rose     // are identical.
32460bd88d3SJordan Rose     if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
32551327f92SJordan Rose       return false;
3266f2f3900SJordan Rose     // If either expression comes from a macro then don't warn even if
32751327f92SJordan Rose     // the expressions are identical.
32851327f92SJordan Rose     if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
32951327f92SJordan Rose       return false;
33070e7e871SJordan Rose 
33151327f92SJordan Rose     // If all children of two expressions are identical, return true.
33251327f92SJordan Rose     Expr::const_child_iterator I1 = Expr1->child_begin();
33351327f92SJordan Rose     Expr::const_child_iterator I2 = Expr2->child_begin();
33451327f92SJordan Rose     while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
33570e7e871SJordan Rose       if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
33651327f92SJordan Rose         return false;
33751327f92SJordan Rose       ++I1;
33851327f92SJordan Rose       ++I2;
33951327f92SJordan Rose     }
34070e7e871SJordan Rose     // If there are different number of children in the statements, return
34170e7e871SJordan Rose     // false.
34251327f92SJordan Rose     if (I1 != Expr1->child_end())
34351327f92SJordan Rose       return false;
34451327f92SJordan Rose     if (I2 != Expr2->child_end())
34551327f92SJordan Rose       return false;
34670e7e871SJordan Rose   }
34751327f92SJordan Rose 
34870e7e871SJordan Rose   switch (Stmt1->getStmtClass()) {
34951327f92SJordan Rose   default:
35051327f92SJordan Rose     return false;
35160bd88d3SJordan Rose   case Stmt::CallExprClass:
35251327f92SJordan Rose   case Stmt::ArraySubscriptExprClass:
3531a3320e4SAlexey Bataev   case Stmt::OMPArraySectionExprClass:
3547ac9efb0SAlexey Bataev   case Stmt::OMPArrayShapingExprClass:
355*13a1504fSAlexey Bataev   case Stmt::OMPIteratorExprClass:
35651327f92SJordan Rose   case Stmt::ImplicitCastExprClass:
35751327f92SJordan Rose   case Stmt::ParenExprClass:
35870e7e871SJordan Rose   case Stmt::BreakStmtClass:
35970e7e871SJordan Rose   case Stmt::ContinueStmtClass:
36070e7e871SJordan Rose   case Stmt::NullStmtClass:
36151327f92SJordan Rose     return true;
36270e7e871SJordan Rose   case Stmt::CStyleCastExprClass: {
36370e7e871SJordan Rose     const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
36470e7e871SJordan Rose     const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
36570e7e871SJordan Rose 
36670e7e871SJordan Rose     return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
36770e7e871SJordan Rose   }
36870e7e871SJordan Rose   case Stmt::ReturnStmtClass: {
36970e7e871SJordan Rose     const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
37070e7e871SJordan Rose     const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
37170e7e871SJordan Rose 
37270e7e871SJordan Rose     return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
37370e7e871SJordan Rose                            ReturnStmt2->getRetValue(), IgnoreSideEffects);
37470e7e871SJordan Rose   }
37570e7e871SJordan Rose   case Stmt::ForStmtClass: {
37670e7e871SJordan Rose     const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
37770e7e871SJordan Rose     const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
37870e7e871SJordan Rose 
37970e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
38070e7e871SJordan Rose                          IgnoreSideEffects))
38170e7e871SJordan Rose       return false;
38270e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
38370e7e871SJordan Rose                          IgnoreSideEffects))
38470e7e871SJordan Rose       return false;
38570e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
38670e7e871SJordan Rose                          IgnoreSideEffects))
38770e7e871SJordan Rose       return false;
38870e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
38970e7e871SJordan Rose                          IgnoreSideEffects))
39070e7e871SJordan Rose       return false;
39170e7e871SJordan Rose     return true;
39270e7e871SJordan Rose   }
39370e7e871SJordan Rose   case Stmt::DoStmtClass: {
39470e7e871SJordan Rose     const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
39570e7e871SJordan Rose     const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
39670e7e871SJordan Rose 
39770e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
39870e7e871SJordan Rose                          IgnoreSideEffects))
39970e7e871SJordan Rose       return false;
40070e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
40170e7e871SJordan Rose                          IgnoreSideEffects))
40270e7e871SJordan Rose       return false;
40370e7e871SJordan Rose     return true;
40470e7e871SJordan Rose   }
40570e7e871SJordan Rose   case Stmt::WhileStmtClass: {
40670e7e871SJordan Rose     const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
40770e7e871SJordan Rose     const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
40870e7e871SJordan Rose 
40945d71a27SJordan Rose     if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
41045d71a27SJordan Rose                          IgnoreSideEffects))
41145d71a27SJordan Rose       return false;
41245d71a27SJordan Rose     if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
41345d71a27SJordan Rose                          IgnoreSideEffects))
41445d71a27SJordan Rose       return false;
41545d71a27SJordan Rose     return true;
41670e7e871SJordan Rose   }
41770e7e871SJordan Rose   case Stmt::IfStmtClass: {
41870e7e871SJordan Rose     const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
41970e7e871SJordan Rose     const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
42070e7e871SJordan Rose 
42170e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
42270e7e871SJordan Rose                          IgnoreSideEffects))
42370e7e871SJordan Rose       return false;
42470e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
42570e7e871SJordan Rose                          IgnoreSideEffects))
42670e7e871SJordan Rose       return false;
42770e7e871SJordan Rose     if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
42870e7e871SJordan Rose                          IgnoreSideEffects))
42970e7e871SJordan Rose       return false;
43070e7e871SJordan Rose     return true;
43170e7e871SJordan Rose   }
43270e7e871SJordan Rose   case Stmt::CompoundStmtClass: {
43370e7e871SJordan Rose     const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
43470e7e871SJordan Rose     const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
43570e7e871SJordan Rose 
43670e7e871SJordan Rose     if (CompStmt1->size() != CompStmt2->size())
43770e7e871SJordan Rose       return false;
43870e7e871SJordan Rose 
43970e7e871SJordan Rose     CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
44070e7e871SJordan Rose     CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
44170e7e871SJordan Rose     while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
44270e7e871SJordan Rose       if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
44370e7e871SJordan Rose         return false;
44470e7e871SJordan Rose       ++I1;
44570e7e871SJordan Rose       ++I2;
44670e7e871SJordan Rose     }
44770e7e871SJordan Rose 
44870e7e871SJordan Rose     return true;
44970e7e871SJordan Rose   }
45070e7e871SJordan Rose   case Stmt::CompoundAssignOperatorClass:
45151327f92SJordan Rose   case Stmt::BinaryOperatorClass: {
45270e7e871SJordan Rose     const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
45370e7e871SJordan Rose     const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
45451327f92SJordan Rose     return BinOp1->getOpcode() == BinOp2->getOpcode();
45551327f92SJordan Rose   }
45651327f92SJordan Rose   case Stmt::CharacterLiteralClass: {
45770e7e871SJordan Rose     const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
45870e7e871SJordan Rose     const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
45951327f92SJordan Rose     return CharLit1->getValue() == CharLit2->getValue();
46051327f92SJordan Rose   }
46151327f92SJordan Rose   case Stmt::DeclRefExprClass: {
46270e7e871SJordan Rose     const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
46370e7e871SJordan Rose     const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
46451327f92SJordan Rose     return DeclRef1->getDecl() == DeclRef2->getDecl();
46551327f92SJordan Rose   }
46651327f92SJordan Rose   case Stmt::IntegerLiteralClass: {
46770e7e871SJordan Rose     const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
46870e7e871SJordan Rose     const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
469f3544e91SJordan Rose 
470f3544e91SJordan Rose     llvm::APInt I1 = IntLit1->getValue();
471f3544e91SJordan Rose     llvm::APInt I2 = IntLit2->getValue();
472f3544e91SJordan Rose     if (I1.getBitWidth() != I2.getBitWidth())
473f3544e91SJordan Rose       return false;
474f3544e91SJordan Rose     return  I1 == I2;
47551327f92SJordan Rose   }
47651327f92SJordan Rose   case Stmt::FloatingLiteralClass: {
47770e7e871SJordan Rose     const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
47870e7e871SJordan Rose     const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
47951327f92SJordan Rose     return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
48051327f92SJordan Rose   }
48170e7e871SJordan Rose   case Stmt::StringLiteralClass: {
48270e7e871SJordan Rose     const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
48370e7e871SJordan Rose     const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
484b6100301SJordan Rose     return StringLit1->getBytes() == StringLit2->getBytes();
48570e7e871SJordan Rose   }
48651327f92SJordan Rose   case Stmt::MemberExprClass: {
48770e7e871SJordan Rose     const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
48870e7e871SJordan Rose     const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
48970e7e871SJordan Rose     return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
49051327f92SJordan Rose   }
49151327f92SJordan Rose   case Stmt::UnaryOperatorClass: {
49270e7e871SJordan Rose     const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
49370e7e871SJordan Rose     const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
4946f2f3900SJordan Rose     return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
49551327f92SJordan Rose   }
49651327f92SJordan Rose   }
49751327f92SJordan Rose }
49851327f92SJordan Rose 
49951327f92SJordan Rose //===----------------------------------------------------------------------===//
50051327f92SJordan Rose // FindIdenticalExprChecker
50151327f92SJordan Rose //===----------------------------------------------------------------------===//
50251327f92SJordan Rose 
503e8a2c18bSBenjamin Kramer namespace {
50451327f92SJordan Rose class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
50551327f92SJordan Rose public:
checkASTCodeBody(const Decl * D,AnalysisManager & Mgr,BugReporter & BR) const50651327f92SJordan Rose   void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
50751327f92SJordan Rose                         BugReporter &BR) const {
5084aca9b1cSAlexander Kornienko     FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
50951327f92SJordan Rose     Visitor.TraverseDecl(const_cast<Decl *>(D));
51051327f92SJordan Rose   }
51151327f92SJordan Rose };
512e8a2c18bSBenjamin Kramer } // end anonymous namespace
51351327f92SJordan Rose 
registerIdenticalExprChecker(CheckerManager & Mgr)51451327f92SJordan Rose void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
51551327f92SJordan Rose   Mgr.registerChecker<FindIdenticalExprChecker>();
51651327f92SJordan Rose }
517058a7a45SKristof Umann 
shouldRegisterIdenticalExprChecker(const CheckerManager & mgr)518bda3dd0dSKirstóf Umann bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) {
519058a7a45SKristof Umann   return true;
520058a7a45SKristof Umann }
521