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