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