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